Skip to main content
One Python package (ionworks 0.1.0), protocol version history with live preview, and the Design lab

Introducing ionworks: one package for everything Ionworks in Python

Already using ionworks-api, ionworksdata, ionworks-schema or iwutil? The migration guide maps every old import to its new home.
Working with Ionworks from Python now takes a single install. pip install ionworks gives you the API client, data processing, pipeline building and shared utilities in one package, with one version and one set of docs:
Why we did this
  • One install, always in step. You no longer have to keep ionworks-api, ionworksdata, ionworks-schema and iwutil at compatible versions. They ship together, so they always work together.
  • Laid out like the app. iw.data for measurements and processing, iw.pipeline for building fits and validations, iw.api for everything on the platform.
  • One place to look. A single documentation site, changelog and repository.
  • Up to date. Python 3.12 through 3.15, including the newest Python that PyBaMM supports.
Moving overYour existing scripts keep working on the current packages, which now print a notice pointing here. When you’re ready, the migration guide maps every old import to its new home, or you can ask your coding agent to run the migrate-to-ionworks skill from the Ionworks skills and do it for you. Install ionworks in a fresh environment: it can’t share one with ionworks-api.We’re starting at 0.1.0 so we can refine the API with your feedback before 1.0. Let us know what you think.

Protocol version history and a live preview

Protocols now keep a version history. Editing a protocol no longer creates a same-named copy: Save records the next numbered version, with an optional name (after an AI edit, the name starts as your prompt). Older versions open read-only with a Restore option, and the header shows when you have unsaved changes and which version they’re based on.While you edit, a new Preview tab simulates the protocol on your parameterized model’s equivalent circuit model and redraws as you change it, so you can check a protocol behaves as intended before running a full simulation.

Design lab

The new Design lab (under Optimize, and from a cell specification or parameterized model page) lets you explore cell designs against a metric suite’s surrogate. Drag design parameters and every metric updates instantly, with a spider plot and deltas against the baseline design. Meet targets finds a design that hits the metric targets you set. You can compare several cell specifications side by side in both views, and train surrogates for several specifications in one go.

Versions for parameterized models

Parameterized models can now have versions. Save a new version from the model page (or with create_version() in the Python API), keep the original’s name, and compare any two versions side by side. Model lists show one row per model.
Improvements
  • Simulations in the sidebar. A project-wide Simulations list under Simulate, also shown on Project Home, includes runs made outside a study. A New Simulation button starts one from there.
  • A dashboard for every study. A study’s Dashboard tab creates its dashboard on first visit, and the empty state lists the study’s runs, models, protocols, inputs and metrics to plot. The plot builder offers every variable of a run’s model, computing ones that weren’t stored on request.
  • State of charge in study plots, on either axis (e.g. voltage against SOC), for any model that can compute it.
  • Metric scatter plots are coloured by condition, with a legend, so a sweep no longer reads as one cloud. Choose what drives the colour with the Color by option.
  • Clearer plot tooltips. Simulation tooltips show the x value and a short default set of fields. Pick up to 20 extra fields under Plot appearance → Tooltip fields.
  • Linked parameters read as formulas. A linked parameter’s expression shows parameter symbols and rounded numbers; hover for the full name or exact value, click a symbol to jump to that parameter. Edit a parameter’s symbol on the model page.
  • Protocols show their sub-procedures. A protocol that calls sub-procedures (such as a Maccor master procedure) now shows them in its UCP, flowchart and plain-English views.
  • Better section detection for linked protocols. For a measurement linked to a protocol, sections (pulses, full loads) are identified using the protocol’s planned steps rather than guessed from the data alone.
  • Live sync shows the Ionworks Sync version each PC runs, its schedule and any upload-rule errors, and offers an update when a newer version is available. Maccor files with four-digit extensions now sync, upload rules can be edited on the PC, and each run reports how many files the rules left out.
  • Organization admins can hide more pages. Every sidebar page can now be hidden per organization, and links to hidden pages are hidden everywhere else too.
Fixes
  • Dashboard plots no longer warn that pack or module voltages are “outside the physical range”.
  • Time-series reads no longer fail for measurements uploaded from the SDK without the cycle capacity and energy columns.
  • Simulations of unstructured (3D) DFN models now include State of charge.
  • Cell names on the Cells page link to the cell again, and a specification’s parameterized-models tab follows the Parameterized Models page setting.
  • The study report’s upload guide link points at the right docs page.
  • Design lab labels, parameter names, values and units no longer clip.
Fixes
  • CycleAgeing.plot_fit_results() draws the model and residual lines through sparse targets’ scored points instead of leaving them invisible.
  • Stored parameter sets keep only the hysteresis branches the model actually uses. The check_for_hysteresis option of iwp.util.clean_parameters is removed.
Improvements
  • Dashboards from code. client.dashboard lists, previews, creates, updates, renders and deletes dashboards and plots.
  • Function-valued design parameters. A design parameter can be a lookup table, {"x": [...], "y": [...], "interpolator": "linear"}, so you can screen candidates such as electrolyte conductivity curves as a batch without storing a model for each.
  • Parameterized model versions: create_version() and list_versions(). get_parameter_values() takes names and match to read only the parameters you need.
  • Pipelines and simulations: client.pipeline.list_elements(), get_element_job_config() and client.simulation.get_steps().
  • MCP server: new tools create, copy and version parameterized models, read pipeline outputs, manage studies and compare runs, and results are more compact. An expired sign-in now prompts you to reconnect instead of failing every tool call.
Improvements
  • Much faster long simulations. Equivalent circuit model simulations of repeated cycles are dramatically faster (1000 CC-CV cycles in well under a second), and per-step overhead is lower for every model, with unchanged results.
Improvements
  • New manage-dashboards skill: read, author and render dashboards through the SDK.
  • manage-protocols covers protocol versions; run-simulations, manage-projects, run-pipelines and sim-results cover function-valued design parameters, parameterized model versions and the new pipeline and step reads.
Study dashboards and simulation plots, Maccor recorded procedures, MF4 export, and a faster protocol simulator

Simulation plots and study dashboards

Project dashboards can now hold simulation plots as well as measurement plots. Pick runs by filtering the simulations table (including on inputs and metrics), either as a fixed set or as a saved filter rule that picks up new completed runs when refreshed, then preview them in a compact plot drawer and save the plot. Metric plots are scatter plots with hover detail, and time-series legend fields are configurable.A study can now have its own dashboard, kept with the study rather than in the project’s dashboard list. A study’s creator controls its dashboard and which simulations it contains; anyone else can view and preview results, or Copy study to get their own editable copy with its dashboard and plots. The study list shows each study’s creator, with an All / Mine toggle.

See the procedure a Maccor run recorded

Maccor raw (binary) data files, which were previously marked unsupported, are now read for the test procedure the cycler recorded in them. A complete recording is added to the protocol library (or matched to a protocol already there) and linked to the run’s measurement automatically. Raw files uploaded before this change have been re-read.On a measurement page, the protocol now has its own Protocol card: change, link or unlink the protocol, see whether it matches what the cycler recorded, and Replace with what the cycler recorded when it differs. The raw file’s page shows the recorded procedure too.

Export measurements as MF4

The measurement page’s Download data menu now offers MF4 (ASAM MDF4) alongside Parquet and CSV, for use in CANape, asammdf and other MDF tools. Channels carry their units (e.g. Voltage in V), and the download includes a README showing how to read the files with asammdf.

Faster protocol simulations

Long protocol simulations spend much less time outside the solver: a 1,000-cycle ageing protocol runs about 3× faster, with identical results.
Improvements
  • Cycle-level capacity and energy. Measurements and simulations now include Cycle discharge capacity [A.h], Cycle charge capacity [A.h], Cycle discharge energy [W.h] and Cycle charge energy [W.h], which accumulate across every step of a cycle and reset at the next. Existing measurements have been updated, and the columns are included in data downloads.
  • Raw files on the measurement page. A Raw files card lists the files a measurement was built from, what each did (created, replaced or extended it) and links to each file’s page. The Details, Analyses and Raw files panels can now be collapsed.
  • Project Contributors can delete the project content they can create and edit. Deleting the project itself, its members and roles, live-sync sources and raw-data issues stays with Project Admins.
  • Every protocol needs a name. The simulation builder always asks for one, prefilled from an uploaded file or a generated protocol, and won’t run with a name another protocol already uses.
  • Protocol names link to the protocol on the simulation page, in measurement tables and on the lab channel schedule. The simulations table groups its Columns panel and links its Protocol column.
  • Column widths are remembered. A column you resize keeps its width through search and page reloads, on every table.
  • Failed measurements show a red alert icon beside their name instead of a separate column.
  • Live sync sources that are still being set up show amber on the Live sync page, in the top bar and on project Home, instead of looking healthy.
  • Dashboards load faster, fetching all their plots in one request.
  • Parameter metrics. Metric suites can define metrics such as stack thickness or areal capacity, computed directly from a parameterized model’s parameters.
Fixes
  • Simulating a saved protocol fills in every input it references, including inputs used only in its global settings, from the protocol page, a study and the full setup page.
  • Table rows can’t lose their controls. The selection checkbox, View button and row menu can no longer be hidden from the Columns panel.
  • The last row of a table is no longer partly covered by the scrollbar strip on macOS, and single-page tables no longer show a pagination footer.
  • The Voltage components section is only offered for models that have a voltage breakdown.
  • Opening a raw file’s plot no longer fails intermittently right after the file was updated.
Improvements
  • ElectrodeBalanceFromFirstCycleEfficiency supports composite electrodes (e.g. graphite/SiOx) through options, and now computes the formation loss against the positive electrode’s capacity, so it follows design changes to loading. "Nominal cell capacity [A.h]" is no longer an input, and results change for existing configs.
Fixes
  • Data fits and validations now use the model’s saved simulation settings (mesh and solver) instead of the defaults.
  • CycleAgeing warns with the cause whenever a metric is scored as a failed evaluation, and a fit where every evaluation fails raises an error instead of returning the initial guess.
Improvements
  • Every record links to the web app. Detail get calls return url (the record’s page in the app) and api_url (its canonical endpoint).
  • Per-run simulation settings. Simulation batches take simulation_settings (solver, var_pts, submesh_types, spatial_methods, discretisation_kwargs), overriding the model’s and parameterized model’s settings for that run. discretisation_kwargs can also be saved on models and parameterized models.
  • Repeat inline simulations reuse stored results. Submitting the same inline parameterized model again reuses the existing one instead of creating a new copy or failing on its name.
  • Protocol groups. client.protocol_group creates, lists, updates and deletes groups, and protocols take protocol_group_id.
  • Projects carry your own access. Project records include my_role and my_permissions for the caller, and no longer embed every member’s role, so project lists are much smaller.
  • Metric suite surrogates. client.metric_suite.create_surrogate(...) trains a model that predicts a suite’s KPIs anywhere in a range of design variables without simulating.
  • Sites have a timezone (Site.timezone, an IANA name defaulting to America/New_York).
Fixes
  • Under termination="events", a constant-current or constant-power step whose last logged sample belongs to the next step now takes its end value and setpoint from its own samples, so simulated steps no longer stop early.
Fixes
  • Voltage sweeps (e.g. slow cyclic voltammetry) with no explicit duration run until their setpoint reaches an end condition, instead of stopping at 24 hours.
  • Sub-procedure jumps in protocols imported from Maccor, Arbin or UCP files resolve correctly, and an unresolved block-level goto is reported when the protocol is saved.
Improvements
  • run-simulations covers per-run simulation settings, metric suite surrogates and protocol groups.
  • manage-protocols and discover-api document protocol groups.
  • manage-projects, manage-cells, run-pipelines and discover-api link to records through their url.
  • manage-equipment documents site timezones.
MATLAB and Simulink (Beta) export, 3D simulations, model builders, and plottable raw files
The Download button on a parameterized model’s page is now a menu: the existing model and parameters JSON, MATLAB code, and Simulink block (Beta). The Simulink block has been checked in Octave but not yet run in MATLAB/Simulink. Both exports use the model’s saved simulation settings, so the exported model matches what runs in Studio. Current and ambient temperature are always inputs, and initial SOC is an input for ECM and lithium-ion models. The MATLAB export includes a README and a run_example.m, and models with algebraic equations (such as ECM and DFN) work in both exports.

3D simulations

Models can now start from a 2D (x-z) or 3D (x-y-z) unstructured DFN preset in the model create form, and their results have a new Spatial field plot. It draws the field on the cell’s mesh in the browser, with a time slider, a cutaway along any axis, mesh edges and a fixed colour bar.

Build a model’s parameters from any cell spec

A model builder is a recipe, saved on a model, that turns a cell specification into that model’s parameter set. Each parameter comes from the cell spec (with units converted automatically), a fixed value, or a calculation whose inputs can themselves be read from the spec. Test on example runs an unsaved recipe against an example spec, and Build model in a cell spec’s Parameterized models tab saves the result. Builders are also available in the Python API as client.model_builder.Parameterized models can now keep a calculated parameter as the calculation that produces it rather than a frozen number, so overriding one of its inputs in a simulation (e.g. an active material fraction) recomputes it.

Raw files you can open, plot and triage

Every file in Data → Raw data now opens its own page. A file that parsed is plotted with the same plot card as a measurement (time series, cycles, dV/dQ, step filters); a file that didn’t shows its findings with Retry and Download. Files waiting for a decision or for their cell to be registered are counted on the Measurements sidebar item and announced on project Home and Measurements, linking to a review view. Files in a format no reader recognizes are marked Unsupported and hidden from the list by default, so they no longer bury the failures that need attention.
Improvements
  • Models belong to a project. A model is visible only in its own project, and each project has its own copy of the built-in models. Model names are unique per project.
  • Report a cell or test as failed. A Report failure dialog on a measurement marks either that test or the whole cell as failed, with a reason. A failed cell fails every test on it; a failed test leaves the cell alone.
  • List pages remember their view. Filters, search, sort and page size are kept when you leave a list and come back in the same tab, on raw data, measurements, cells, materials, models, parameterized models, pipelines, protocols, optimizations and dashboards.
  • Simulation plot boards are saved. Plots you add and the layout you arrange on a simulation’s page are restored the next time anyone opens it.
  • Copy a plot to the clipboard from the plot toolbar, ready to paste into a doc or slides. Downloaded and copied PNGs now use the plot’s background colour and have padding on every edge.
  • The Voltage components plot is opt-in. It is shown with a Show voltage components button, and only offered when the current keeps one sign.
  • Filter pills on status columns show ticks for what the grid shows, with Only to keep a single value and Select all to clear the filter.
Fixes
  • Re-uploading a fuller cycler export no longer fails when the cycler renumbered its cycle counter between exports.
  • Auto-fixing a reversed current sign now flips power too, so charge and discharge energy are no longer swapped.
  • Fits whose validation produced no score no longer stay “processing” after they finish, and jobs that will never finish are now marked failed instead of showing “pending” indefinitely.
  • A design optimization or fit where every simulation fails now fails with an error instead of completing with a penalty cost.
  • A cell can no longer be scheduled onto two channels at overlapping times.
  • Icons on light buttons in dark mode match their label’s colour instead of white.
  • A raw file’s page adds one browser history entry and shows one loading screen.
  • Listing a cell’s measurements now returns each measurement’s channel_id.
Improvements
  • New calculations: ElectrodeBalanceFromFirstCycleEfficiency (stoichiometry limits and initial concentrations from electrode geometry, nominal capacity and first-cycle efficiency) and ElectrodeGeometryFromLoading (thickness, active volume fraction and porosity from coating loading and press density).
  • Requires pybamm>=26.10.1.1.
Fixes
  • A fit where every evaluation fails now raises an error instead of returning the initial guess.
  • A composite-electrode MSMR config with hysteresis on only one phase gives a clear configuration error instead of a bare KeyError.
Improvements
  • client.model.create_from_zoo(...) imports a model from the PyBaMM model zoo and creates both a model and a parameterized model in one call. cell_spec_id is optional, and model constructor arguments go in model_kwargs.
  • Cheaper simulation lookup. client.simulation.list takes protocol_id, state (queued/running/completed/failed) and summary, and parameterized models can be listed without their parameter values. Every simulation record carries its protocol_id and protocol_name.
Fixes
  • Large uploads no longer fail with HTTP 524 on a slow part.
  • Dependency floors across the public packages are raised to versions that actually install and import (e.g. pandas>=2.2.2, pyarrow>=16.0.0).
Fixes
  • Step classification ignores a step’s trailing sample when it carries the next step’s setpoint, so constant-current steps are no longer classified as “Unknown step type”.
Fixes
  • BioLogic exports with C-rate steps or end conditions load on the instrument: C-rates are written as absolute currents against the cell’s nominal capacity.
  • Nested repeat blocks keep the right cycle counts through an Arbin export and re-import.
  • A step_block: written with a name: field now takes that name, so two such blocks validate and goto can target them.
  • A C-rate < x end condition now fires on models without a C-rate variable, such as iwp.models.ECM.
Improvements
  • manage-projects covers project-scoped models, importing from the PyBaMM model zoo, and live calculated parameters.
  • run-simulations and search show how to find and reuse an existing simulation.
  • manage-protocols notes that BioLogic exports need the cell’s nominal capacity.
PDF reports for parameterized models, the data behind every plot, and dashboards that stay yours

PDF reports for parameterized models

A parameterized model’s page has a Report button that downloads a PDF of the model as it stands. Each function-valued parameter is plotted against its input (stoichiometry, state of charge, electrolyte concentration or temperature), with one curve at each of 0, 10, 25, 35 and 45 °C where temperature is an input. Where possible it is also written out as an equation, with a legend giving each referenced parameter’s name and value. A parameter that can’t be plotted is listed in a Not plotted table with the reason. Scalar parameters are tabulated in the same sections as the model’s parameter tabs, after a cover page listing the model type, thermal and ageing options, and description.

See and export the data behind a plot

Dashboard plots, and plots in the measurement plot drawer, have a View source data menu item. It opens one table of the data the plot is drawn from — with the measurement, cell and specification names alongside the values where the plot reads them — and the same table downloads as CSV. Values the plot calculates while drawing are not included, and the dialog says so.

Dashboards stay the way their creator left them

Only the person who created a dashboard can edit or delete it, its plots, or its agent drafts. Everyone else with access can still view it and change plot inputs for themselves (never saved). Anyone whose role can create dashboards (Project Admins and Contributors) can also make their own version of the whole dashboard, or copy a plot to a dashboard of their own. A duplicated dashboard shows where it came from (“Copied from X on 2026-10-11 15:52”). Trying to change someone else’s dashboard explains how to get an editable copy.

Repair a file whose time runs backwards

A raw file that fails the time-ordering check no longer leaves only Accept and continue or Discard this file. The review now shows the offending rows and offers just the repairs that fit the problem, recommended first: rebuild a continuous clock (when a per-step clock was exported instead of total elapsed time), sort rows by time, drop the out-of-order rows, or separate identical timestamps. A repair that doesn’t restore ordering is reported as still needing input rather than marked fixed.
Improvements
  • Choose the agent’s model. A picker under the chat input switches between Opus 5.5 (the default), Sonnet 5.5 and Haiku 5.5, and your browser remembers the choice.
  • Analysis plots read cleanly when a test repeats set-points. Points are drawn in x order as markers, with a line through each set-point’s mean, so a rate table run twice reads as one line instead of a sawtooth. This applies in the plot drawer, dashboards and the analysis page.
  • The protocol generator is faster and fails less often. It no longer gets stuck re-reading the same reference material until it gives up.
Fixes
  • An older export of a running test no longer closes it. A manually uploaded file whose data ended more than two days ago marked the test as finished, so the next, fuller export was refused as not fitting. Runs already closed this way are unchanged.
  • Reported metrics no longer show a misleading number when a threshold is never reached. A metric such as “Charge time (10–80% SOC)” on a charge that stalls before 80% now shows no value.
  • Stacked dashboard plots put the x axis under the bottom row instead of the top. Plots already on a dashboard pick this up when they are re-sent or edited.
  • Paging past the end of a list, for example after a filter shrinks it, returns an empty page on the pipelines list and most others, instead of a server error.
The metric examples below use the ionworkspipeline Python classes; in a pipeline config the same metrics are written as dicts, e.g. {"type": "Crossing", ...}.Improvements
  • A metric can span several steps. Any metric’s step accepts a list of consecutive steps, read as one, e.g. Minimum("Negative electrode potential [V]", step=[2, 3, 4]). Gaps, repeats and descending lists are rejected with a message pointing to ComposedMetric.
  • New Crossing metric, Crossing(variable, crossing_variable, value, step), reads variable at each point where crossing_variable crosses value. SOC and Voltage are now special cases of it, with their configs unchanged.
  • Crossing thresholds can be metrics. value accepts a metric evaluated on the whole solution, so a threshold can depend on an earlier step, e.g. the time for throughput to go from 10% to 80% of a step-0 capacity.
  • by_cycle(step={cycle: step}) reads a different step in each cycle, for a quantity logged at different positions in different cycles.
  • RelativeTime validates as a metric config, on its own, as a threshold, and in design optimizations.
  • DirectEntry references must be in the pipeline’s project. A pipeline_id or cell_spec_id from another project is refused with a permissions error that says how to fix it.
Fixes
  • Pipeline calculations that read a stored measurement (for example an OCP interpolant from a GITT measurement) no longer fail with an authentication error.
  • CycleAgeing no longer saves only a threshold’s cycles for a crossing searched over the whole solve; an unsliced crossing with a cycle-sliced threshold is now rejected.
  • A missing variable in SOC now gives a UserConfigurationError that names it, rather than a bare KeyError.
Fixes
  • Arbin LS_CHAN_* capacity and energy are read as the cumulative channel counters at the end of the previous step, matching the cycler. Protocols that read them after several steps without a counter reset (e.g. sizing GITT pulses from a two-part discharge) had used only the last step. Arbin energy counters now accumulate too.
A plot drawer for measurements, dashboards you can edit yourself, and metadata filters

Plot measurements from the table

The separate comparison page is gone, and so is its 10-measurement limit. Select measurements in any measurement table, click Plot and pick a plot type: time series (with multiple and stacked Y axes), a cycle metric against cycle (optionally relative to a reference cycle), voltage against capacity, dQ/dV and dV/dQ, or an analysis when every selected measurement has the same kind. A plot type the selection can’t support is shown disabled with the reason (“4 of 12 have no cycle data”).The plot opens in a resizable drawer over the table, which stays usable underneath: ticking or unticking rows adds or removes measurements from the plot. Closing the drawer collapses it to an edge tab, and the plot survives a reload. A finished plot can be saved as a project-wide template, which then appears as a plot type, or sent to a dashboard — either for the measurements you picked, or for every measurement matching the table’s current filters, so new matches appear on their own. A dashboard plot draws up to 500 measurements (250 for analysis plots), and the builder says so when a scope is larger.Your measurement selection now persists across pages, filters, tables and reloads within a project, with its actions in the table toolbar. Other paginated tables clear their selection when you change page, so a bulk action only ever applies to rows you can see.

Dashboards you can edit yourself

  • Build a plot without the agent. A dashboard’s New plot offers Build a plot, which starts from the project’s measurement table with its search, filters and tags, then the same plot types and controls as the drawer, with a live preview. Builder plots can be rebuilt in place with Edit plot, and each card shows whether it came from the builder or the agent.
  • Change titles, axis labels and colours from the plot’s Configure drawer, including five palettes (among them colour-blind-safe and sequential). The agent never overwrites your choices; when one of its edits would, the review card lets you keep yours or take its version.
  • See and edit the code behind an agent plot. Edit code (or View code without edit rights) shows the plot’s data plan, transform and parameters with a live preview. Save is only enabled once the edited code has run without errors, and a concurrent edit is refused rather than overwritten.
  • Know what a plot shows. Each plot has an editable one-line description, lists the filters that selected its data, and its record count opens a list of the records it read (up to 500), grouped by cell, each linking to its page.
  • Plot cell design data. Dashboard plots can read electrode and component properties (thickness, porosity, loading, active fraction, and separator, electrolyte and case properties) and chain from a spec’s components to their materials’ datasets.

Filter measurements by any metadata

Measurement tables gain a column for every metadata field on the measurement, its cell instance and its cell specification — anode loading, cathode porosity, cycler, ratings, material properties and more — all hidden until you show them. Numeric fields filter with a range slider over a histogram of the project’s values; text fields filter by value. The columns panel is searchable and grouped, and CSV export writes these values as columns. Column headers are the field’s full path in the specification (for example anode.properties.thickness (um)), the same path a pipeline uses to read it (see Pipeline below).
Improvements
  • Download measurements and analyses as CSV as well as parquet, at full resolution, from a format menu on their download buttons.
  • Move, resize and dock the agent chat. Drag the panel or its launcher anywhere, resize it from any edge, or dock it to the right so the page reflows beside it. Minimized while docked, it becomes an edge tab that shows when a reply is running or has finished.
  • Datasheet fields on cell specifications: charge and discharge temperature limits, maximum pulse current and duration, standard charge and cutoff currents, 1 kHz ACIR, DCIR with its pulse length and SOC, and cycle life. The protocol generator uses the charge currents, pulse limit and temperature limits.
  • Section analyses are versioned. After a measurement is extended or re-exported, its analyses show once, labelled with the time their data runs through, with earlier versions in a menu and as tabs on the analysis page.
  • A raw file can update the measurement it belongs to, extending it when the file continues an existing test rather than creating a duplicate.
  • Raw-data review shows the file beside the measurement it matched, with both spans on one timeline and a different procedure flagged.
  • Process pending files on the Raw Data page queues a project’s waiting files, including ones waiting for their cell.
  • Drive-cycle uploads for simulations are easier. Drop several files at once to fill matching slots by name, use one profile for every slot, and see each file’s points, duration and current range as it is checked. An unreadable file is refused on its own row, and a protocol missing a drive cycle now fails with a message naming it instead of simulating without it.
  • Formation detection handles noisy loggers and narrow voltage windows better.
  • Faster page loads inside a project, and much faster simulation results for long solutions.
Fixes
  • Projects that have run simulations can be deleted. Deleting one failed with “Invalid reference”.
  • ECM fits and validations with a start or end step work on stored measurements. They were rejected for a missing step column.
  • Study validation with an open-ended step range no longer drops steps past the first 10,000. A step range on a measurement without step data is now an error.
  • A rolled cycler file that starts a few seconds before the stored data ends is appended instead of being held for review.
  • Cancelling a job, simulation, optimization or pipeline you can only view is now refused with a permissions error before anything is stopped.
  • Icons and chips in table cells are vertically centred in every table.
Improvements
  • DirectEntry can keep part of a pipeline. DirectEntry(pipeline_id=..., keep=[...]) takes only the named parameters from a completed pipeline, for example a half-cell fit’s kinetics without its coin-cell geometry.
  • DirectEntry can read a cell specification. DirectEntry(cell_spec_id=..., mapping={...}) maps each parameter to a path in the spec (e.g. "anode.properties.thickness", "ratings.capacity") and converts each value to the unit in the parameter’s name, including offset units such as °C to K. provenance records where each value came from.
  • SimplePipeline is deprecated in favour of Pipeline, which takes the same elements. It will be removed no earlier than November 2026; a migration guide is in the docs.
Fixes
  • A log-scale fit parameter reached through a chain of parameter links is no longer rejected as unused when the links are set out of order.
  • CycleAgeing metrics read the right cycle when the solver skips an infeasible experiment cycle. Later cycles were shifted by one, reading the wrong values or failing the fit.
  • Post-fit validation retries an objective whose worker was lost, instead of dropping it from summary_stats and validation_results.
  • Least-squares fits with an objective initialized from "Initial voltage [V]" or "Initial SOC [%]" no longer stop at their starting point when a fitted parameter also changes the initial state.
  • Creating a parameterized model no longer fails when a custom model has a lithiation or delithiation parameter without its counterpart.
Improvements
  • client.simulation.protocol() and protocol_batch() accept protocol_id to run a saved protocol, and protocol_batch() accepts conditions, an explicit list of runs each with its own parameters.
  • client.simulation.get_statuses(simulation_ids) returns many statuses in one call.
  • client.simulation.delete() and client.parameterized_model.delete(), so a project holding either can be cleaned up and deleted from the SDK.
  • client.cell_measurement.time_series(..., row_range=(start, stop)) downloads only that window of rows.
  • Simulation configs are checked for unknown keys. A misspelt or misplaced key raises a ValueError naming it, where it was previously ignored.
  • A pipeline data fit reports its best cost in fit.cost.
  • client.simple_pipeline is deprecated. Each method warns and names its client.pipeline equivalent.
  • POST /cell_measurements/export accepts format="csv", and GET /analyses/{id}/csv downloads an analysis as CSV.
  • Analyses created without columns have them filled in from the uploaded file.
Improvements
  • DataLoader.from_db with first_step / last_step downloads only the rows those steps cover instead of the whole time series — a small fraction of the data for one cycle of a long test.
Improvements
  • BioLogic |Q| limits are supported, so a partial-discharge drive cycle stops at the charge it should. Limits relative to an earlier sequence’s charge warn instead of being guessed.
  • A BioLogic protocol whose drive-cycle table doesn’t match its step asks for the profile file instead of failing to load.
  • BT-Test protocols export C-rate step ends.
Fixes
  • Current limits in C-rate mode in BioLogic EC-Lab and BT-Test protocols are read as C-rates. A C/20 taper had been read as a current in mA or A.
Improvements
  • run-simulations covers running a saved protocol by protocol_id, explicit run lists with conditions, get_statuses() and delete().
  • manage-cells covers downloading part of a time series with row_range; manage-projects covers deleting parameterized models.
  • run-pipelines and discover-api mark client.simple_pipeline as deprecated.
Fixes
  • manage-projects and discover-api show client.study methods with the resource ids first and project_id last, matching the SDK.
Measurement tags, cell batches and CAD models, and a lab utilization history

Tag your measurements

Measurements can carry free-form tags — “baseline”, “rpt”, “batch-7” — added the way you would in Notion: type to find one of the project’s existing tags or create a new one. Tags match regardless of case and reuse the project’s existing spelling. Click a tag chip in any measurement table to filter by it, and a second to narrow further; tag several measurements at once; and find measurements by tag in global search. The spec and instance pages gain the tag column and filter, plus a type filter.Through the API, measurements accept tags on create and PATCH, lists filter with tags_all / tags_any, GET /cell_measurements/tags lists the project’s tags with usage counts, and POST /cell_measurements/tags/bulk adds and removes tags on up to 1000 measurements.

Cell batches and CAD models

  • Batches are records of their own. A cell’s manufacturing lot used to be a text field on each instance. It is now a batch belonging to a cell specification, with a name, notes, manufacture date and properties. Existing batch text has been converted into batches. Deleting a batch keeps its instances. This changes the API: cell instances replace batch with a writable batch_id and a read-only batch_name, and batches have their own endpoints under /cell_specifications/{id}/cell_batches and /cell_batches/{id}.
  • Attach a CAD model to a cell specification (.step, .iges, .stl, .obj, .ply, .glb, .off, up to 100 MB). A rendered thumbnail shows on the spec page and in the Cells table.

Lab: utilization history and channel checks

  • A Utilization history page shows the cycler fleet over time as bars stacked by state (occupied, stale, free, out of service), from 30 days to 10 years, daily to annually, as a share or as a channel count. Open it from History under the utilization figure.
  • Scheduling checks channel ratings. The Schedule dialog shows the voltage and current range the protocol reaches, and flags any channel whose ratings it would exceed (“Draws 7.5 A, rated 5 A”) or whose ratings are unknown. It warns but does not block.
  • A test request shows what actually happened once it starts: the channel and window it ran on, a link to the measurement it produced, actual against estimated duration, and live channel data while it runs. Schedule is now the first row action in the Test Scheduler.
Improvements
  • Simulate a protocol from its own page. A Simulate button runs the saved protocol against a cell and model you choose, with its inputs prefilled and comma-separated values sweeping. Full setup opens the full form with the protocol preselected.
  • Looping protocols no longer need a setting raised. Max backward jumps now defaults to 1000 and has left the simulation forms; a simulation that exceeds it offers Rerun with higher limit.
  • Cycles plots for every simulation, not only Cycle Aging (EIS excepted).
  • Auto-generated analyses open on a plot suited to their kind: retention against cycle for cycling, capacity against C-rate for a rate test, resistance against SOC for a pulse sweep, charge and discharge capacity for formation.
  • Rate-capability analyses record each step’s start and end voltage, so a step that began below the upper cutoff is visible as such rather than looking like poor rate capability.
  • Analysis detection covers more test shapes. Staircase charges and pulses logged in stages are read as one load, GITT and incremental-OCV titrations are found as pulse sections, capacity-capped rate tests keep their slow and fast steps, and a record that changes voltage window between tests (formation then rate tests, for example) reads each test against its own window. Stored analyses have been re-derived.
  • Invite a member as Member or Admin. The Members invite box has a role choice defaulting to Member; inviting someone who is already a member keeps their role.
  • Faster time-series loading for large measurements, which now fetch only the part of the file a plot needs.
  • Deleting a study says its simulations are kept, and how to delete them first if you want to. Study simulation counts stay current.
  • The project members panel says clearly when everyone in the organization is already on the project.
  • Simulation actions in study, model and protocol grids now show only when you can carry them out.
  • The Cells table gives the name column most of its width; measurement tables beside a details card no longer hide their toolbar on a laptop screen.
Fixes
  • Project Contributors can create pipelines. Creating one failed for members whose organization role was Member.
  • The protocol generator no longer puts cutoffs on its own safety limits. A step ending on or past the protocol’s safety limit is now an error, so a generated test no longer aborts in its first cycle.
  • Older Data Fit and Validation results draw their plots again, for jobs from before March 2026 that showed a legend and no plots.
  • Adding a time-series plot to a simulation in a study loads it. It could sit on “Loading variables” indefinitely.
  • Comparing measurements keeps the Cycles tab when both have cycle data.
  • Table search is consistent as you type: a whole word no longer returns more loosely related rows than a partial one.
  • The specification-name filter on the Measurements list applies. It showed the pill but kept every row.
  • A material’s Used by cell specifications table no longer empties on scroll.
  • The optimizations list and the lab utilization plot fill the page height.
Improvements
  • iwp.Parameter is immutable. The set_* methods are replaced by copies: with_bounds, with_initial_value, with_fitting_scale, with_normalize, with_prior and with_initial_guess_distribution. Assigning p.bounds or p.initial_value raises, naming the method to use instead.
  • A half-cell GITTModel can start from "Initial voltage [V]". It used to fail, or, with a full-cell parameter set, start at the wrong voltage.
Fixes
  • Objective-level constraints are applied with every SciPy optimizer. ScipyMinimize (all methods) and ScipyShgo silently ignored them.
  • The regularization docs now state that a penalty contributes w * fun**2, not w * fun, so fun should not be squared beforehand.
Improvements
  • Manage memberships from the SDK. client.organization gains members(), get_member(), invite(), set_role(), deactivate(), reactivate(), resend_invite() and remove(); client.project gains roles(), add_member(), invite_member(), update_member() and remove_member(). Invites take a role and default to Member.
  • client.analysis.create(..., plots=[...]) stores plot presets for an analysis, validated against its columns.
  • The MCP server can run simulations, with run_simulation, run_simulation_batch and wait_for_simulations.
  • POST /jobs is retired and returns 410 Gone naming the endpoint to use instead: /pipelines, /simulations/with-template/batch, /optimizations or the ECM fit endpoints.
Fixes
  • A malformed id returns 400, not 500 — for example client.job.cancel(None).
  • NaN or Infinity in analysis metadata returns 400 naming the offending key, instead of 500.
Improvements
  • generate_experiment splits a CC-CV charge logged as one step into a CC step and a CV step, so long cycling replays stay within the cell’s voltage window. Pass split_cc_cv=False for the previous behaviour.
  • Step typing works for sub-mA coin-cell data. Rest and constant-current thresholds scale with the cell’s rated capacity (pass cell_spec), or with the data’s own current, instead of typing every step as Rest.
  • Unparseable numbers warn. Values like "N/A" in voltage or current columns are reported with the column and examples rather than silently becoming null.
  • Step labels and groups are removed. iwdata.steps.label_* and validate are gone, steps no longer carry Label / Group number, and the gitt_to_ocp transform is removed (use rest_to_ocp).
Fixes
  • Neware BTSDA flat CSVs map Cycle Index / Step Index, so cycles no longer collapse into one, and capacity and energy columns read as floats.
  • The empty-column warning from Excel readers is silenced.
Improvements
  • run-pipelines replaces run-simple-pipelines, steering fits to regular pipelines so they appear in the web app.
  • run-simulations covers running simulations through the MCP server.
  • discover-api lists the new membership methods; manage-cells documents analysis plot presets, measurement tags and cell batches; process-data documents passing a cell spec for coin-cell step typing.
Stacked and multi-series plots, and pipelines that record the data they ran against

Stacked and multi-series plots

Measurement time-series plots gain stacked rows, the way a cycler’s own software lays them out. Add row puts a new band under the plot on the same x axis, each with its own left and optional right axis, and a single hover box reads every band at the cursor. Every line on an axis shares that axis’s colour and differs by dash, so matching a line to its scale never depends on colour alone. The right axis of the first row is now drawn dotted.Analysis plots draw more than one series. Split a table by a text column (charge vs discharge pulses, for example) to get one line per value instead of a zig-zag joining them, overlay several columns, put one on a right axis, and stack rows as on the measurement plot. Analyses can carry named views — OCV and resistance against SOC, pulse power against SOC, capacity against C-rate — and the view on screen can be linked directly.

Pipelines record exactly which data they ran against

Every pipeline element now records the measurements and time windows it read. A new panel on the pipeline page shows each pinned span next to the measurement’s current span, so you can see at a glance when a measurement has grown since a fit was run, or is no longer available. Existing pipelines have been backfilled.
Improvements
  • The Validation Report compares temperature as well as voltage when the model is thermal and the measurement has a temperature channel. A pair whose measurement was never instrumented says so in one line rather than drawing empty axes.
  • Simulation time-series plots take a step filter in the same syntax as the measurement filters (1:3,5), can use any loaded column as the x axis (voltage against capacity, for example), and show cycle and step on hover.
  • Validation sections load in a single request, and returning to the full view after zooming no longer refetches.
  • Simulation results load faster, as compact files the page can zoom within without going back to the server.
  • Parameterized-model lists are lighter for projects with uploaded custom models, which were sending the full model with every row.
  • The in-app assistant starts answering within a few seconds. It now says what it is looking up before it looks, and finds a record you name by searching for it rather than walking the whole project.
  • Fit progress is tracked per array element and per start, so a multistart or array fit reports each run separately.
  • Global search opens a cell instance at its own page, rather than its specification’s list of instances.
  • No white flash when loading the app in dark mode.
  • Name columns keep a usable width on narrow screens; the parameterized-model ID column is shorter and copies the full ID on click.
Fixes
  • Pulse sections find every pulse. Short pulses were rejected whenever the same record also held much longer steps, so a pulse test could report under half of its resistance values. A pulse section now also spans the discharges and rests between its pulses, a rate ladder run in duplicate is one ladder, and cycling whose cut-off drifts is counted rather than dropped. Existing analyses do not recompute on their own; new and re-run records carry the corrected numbers.
  • Maccor sub-procedures are read as siblings. Three sub-procedures called in turn were read as nested four levels deep, with every boundary one call late.
  • Variables evaluated later on a stored simulation now match the solve. On a simulation started from a set initial SOC, electrode and electrolyte potentials computed after the fact were offset (by up to ~0.7 V on a DFN). Affected stored results have been corrected.
  • Design optimizations honour the model’s options, including its degradation mechanisms. Previously a design objective ran against a model that could not degrade, so every degradation mode reported zero while the job completed normally. Models saved in the current configuration format were also rejected outright.
  • A pinned time window combined with a first/last step selects the right data. It used to either fail with an unexpected error or fit a slice offset from the intended one. A window that excludes the chosen steps is now a clear error naming the span those steps cover.
  • Organization Admins can choose a project role when adding members. The role dropdown was empty for them; a failure to load roles now shows an error with Retry.
  • Creating a study opens it, so the next simulation goes into the new study rather than the one you were on.
  • The Protocol column filter is back on a study’s simulation list.
  • The simulation form clears a stale cell or model remembered from another project instead of showing a red “not found” error.
  • Pickers say they are loading while loading instead of “No options”, which read as “none exist” — in the channel picker, protocol groups and template pickers among others.
  • A zoomed plot frames a newly added axis on the visible window, not on data just off screen, and zooming back out is instant.
  • The Raw Data page no longer flickers on background refreshes.
  • Table cells no longer show through the scrollbar beside the row-actions column.
  • Older pipelines open reliably. Pipelines that ran before late August could fail to load.
Improvements
  • CycleAgeing scores a target only where it has values. A NaN in a target column now means “not measured here”, so a resistance measured on alternate check-ups can be fitted directly instead of being interpolated first.
  • A fit can target a measurement’s stored analysis. Point a CycleAgeing objective at one measurement — its steps give the experiment and its analysis the targets — with ionworksdata.AnalysisLoader.
  • The fit trace is always recorded, whatever progress sink is in use, so plot_trace() works alongside printed or hosted progress. TraceLoggerSink is deprecated.
Fixes
  • Objective-level penalties and constraints are applied. They were accepted and echoed back but had no effect on the fit, and a submitted config using a symbolic penalty was rejected by validation.
  • A CycleAgeing fit whose experiment comes from a stored measurement can now be built with ionworks_schema and submitted.
  • Fixed a rare failure of multistart half-cell OCP fits when a capacity sweep flattened against a voltage limit.
Improvements
  • Simulation results download as parquet. get_result() still returns a SimulationResult, fetched faster; the new /simulations/{id}/time_series/download and /simulations/{id}/steps/download endpoints redirect to the files directly.
  • Large uploads are more robust. Files from 32 MiB use a multipart transfer, and an upload that hits a gateway timeout is retried once that way.
  • An explicit null in a PATCH clears a nullable field — for example a cell specification’s form_factor, manufacturer or notes, or a model’s description. Omitting a field still leaves it unchanged.
Fixes
  • A refused write returns 403. Updating or deleting a record your key cannot change used to return 500 or 204, even though nothing was changed.
  • Fit results are available the moment a job completes. Reading plots straight after completion could intermittently fail with “No plots are stored”.
Improvements
  • AnalysisLoader loads a measurement’s stored analysis as fit targets.
Fixes
  • DataLoader.generate_experiment keeps cycles and cut-offs. It returned one cycle per step and dropped every termination condition. It now returns one cycle per cycle count with the recorded cut-offs. This changes the shape of a generated experiment, and existing CycleAgeing fits using experiment="from data" will produce different (correct) numbers.
Improvements
  • manage-cells lists the fixed columns of the steps, cycles and time-series tables, so an agent can use them without a discovery call.
  • run-simple-pipelines documents using stored measurements as inputs, with pinned time windows.
Invite collaborators straight into a project, and shorter links to everything in the app

Invite a collaborator straight into a project

Bring someone into a project with just their email address — a partner at a supplier, a consultant, a colleague who has never signed in here. They do not need to be in your organization first, and they do not need an account at all.One step does the whole thing: an unregistered address is sent a sign-up invitation, anyone outside your organization is added to it at the least-privileged level, and they land in the project with exactly the role you picked. Someone already in your organization keeps the role they hold, so inviting a fellow Admin into a project can never change their standing elsewhere. Inviting by email grants organization membership, so it sits with organization Admins; Project Admins continue to add existing members to their own projects.

The app now lives at the site root

Links to everything in the app are shorter. A project is /projects/<id>, your account is /account, organization settings is /organization-settings — the /dashboard segment is gone from every page. It said nothing (everything you see while signed in sat under it) and it was carried by every link you paste into a message, every documentation URL, and every link the Python SDK mints.Everything you have already shared keeps working. Any /dashboard link redirects to the same page at its new address, query string and anchor intact — bookmarks, links in notification emails sent months ago, and links produced by older SDK builds all land where they should.
Improvements
  • The material detail page shows who created it. Creation has been recorded all along; there was no name to display until now. Materials created before the field existed simply omit the row rather than showing a blank.
  • Rate-ladder specific capacity is exported. Discharge and charge specific capacity now flow out alongside their absolute counterparts for the rate-capability sections. A cell whose active mass is unknown emits the absolute figures as before.
  • Analysis plots open on something worth looking at. A plot used to default to the first two numeric columns, which on a section table meant drawing the row’s own index against a second way of counting the same rows. Axes are now chosen by what the columns mean — a cycling analysis opens on capacity against cycle, a pulse section on internal resistance against cycle. Both dropdowns still offer every numeric column.
  • Faster pipeline pages, and bulk actions that no longer move megabytes. Reading a pipeline’s elements, and cancelling or resubmitting them in bulk, were each carrying the full configuration and results of every row they touched, none of which was read. Cancelling a large selection is the most noticeable.
Fixes
  • Formation cycles are grouped by their opening charge. A formation is the one case where a cell arrives empty, so its cycle is led by the charge rather than the discharge. Grouping the other way left out the opening charge — the large, irreversible one that formation exists to measure — which distorted first-cycle coulombic efficiency.
  • A constant-voltage hold counts toward its cycle. The taper that finishes a CC-CV charge starts and ends at the ceiling, so it was not joined to the cycle and charge capacity covered only the constant-current leg. On a C/20 taper that is roughly 9% of the charge. The hold, and the rest that follows it, now belong to their cycle.
  • Rate ladders keep their fastest rungs. A ladder made of charges was judged by where the cell had relaxed to during the preceding rest rather than where the load began, so faster rungs were the ones dropped. A seven-rung ladder now reports seven, and the capacity retention computed against them follows. Existing analyses do not recompute on their own; new and re-run records carry the corrected numbers.
  • A pipeline can build on an earlier fit. An entry naming where its starting parameters come from — a completed pipeline, or a JSON file — now submits. The reference is resolved to real values as you submit, against your own permissions, so an unreachable one is an immediate, explanatory error on the request.
  • The right-hand y-axis on a measurement plot can be cleared again. Once a series was chosen there was no way back to an empty right axis — the “None” option disappeared and the last series could not be removed. Every right-axis series now has a remove control, labelled “Clear right axis” when it is the last one.
  • Single-point plots render. A trace with exactly one point was drawn as a zero-length line, which is invisible; it now shows as a marker, with the axes framed proportionally around it.
  • The account page no longer claims you belong to no organizations while it is still loading them, or if the request fails. That message now appears only when it is actually true.
  • The project members panel no longer hangs on “Loading members…” when there is no organization context; it says so instead.
  • An experiment with no description falls back to its protocol name rather than the literal text “Description not available”.
  • A Project Viewer no longer sees an empty, unlabelled actions column on the parameterized-model lists. The menu items were already hidden; the column itself is now omitted when none of its actions are available.
  • Stored degradation-model parameters are cleaned more thoroughly, including ones a model only reveals while it is being built, and the result is verified against a fresh model before it is saved.
Improvements
  • A value that cannot be sent to the server now fails where you wrote it, naming the field. A live model object, a callback, or a logger placed in a configuration field used to survive locally, arrive as its text representation, and fail server-side far from the cause. Parameter mappings are unaffected — functions and array data in a parameter set are converted as they always were.
A record's section metrics saved as analyses; a timeline of what ran when on a cell; pipeline pages that answer from the pipeline, not its jobs; confidence intervals and sensitivity as pipeline elements

Every section of a record becomes an analysis

When a cycling record finishes processing, the platform now measures each section it found — a formation, a rate ladder, a pulse train, a stretch of cycling — and saves one analysis per section against the parent measurement. The numbers are stored next to every other extracted feature rather than recomputed each time a page asks for them, so they are queryable, plottable and downloadable like anything else.One analysis per section, not one per record: the sections measure different things, and a section that occurs twice — two stretches of cycling at different rates — is two results rather than one. Each carries the window it was measured over, the metrics it produced, and a note saying why any number is missing. Rows the platform derived itself are flagged as such, so a view can separate them from analyses a person uploaded.Two new families of metric come with it, both of which need the cell rather than the record:
  • Specific capacity. Every capacity gains a counterpart in mA.h.g⁻¹, computed from the instance’s active mass.
  • Instance C-rate. The existing rate divides by the capacity this record’s window happened to reach; the new one divides by the capacity the cell actually holds. On a real rate ladder that is the difference between reading 0.16 / 0.39 / 0.79 / 1.58 C and reading the 0.2 / 0.5 / 1 / 2 C rungs the ladder was run at.
Both are siblings rather than conversions — the original metrics keep their meaning, and a consumer picks the one it means by name.

A timeline of what ran when on a cell

The cell instance page gains a Timeline: every measurement on that cell drawn on one shared time axis, docked to the bottom of the viewport as a title bar that expands on demand. The grid answers “what exists”; this answers “when, and with what gaps” — the question a date-sorted list can only be read one row at a time to approximate.Runs that don’t coincide sit on a single line with the name written inside each bar. The solid bar is what the cell actually recorded; where the logged end time disagrees, it is drawn beside it — dashed out to a later logged end, or marked at an earlier one — because the two disagree often enough to be worth seeing.

Pipeline pages answer from the pipeline, not from its jobs

A pipeline’s progress is now computed server-side and served per element, so opening a pipeline no longer means the browser fetching a job and its hundred children one request at a time. On a large multistart fit that was hundreds of requests in a couple of seconds, enough to trip a rate limit with two people on the same page. The page now makes a handful.Alongside it, a cancelled pipeline is now terminal on the wire. Pipelines publish is_terminal and is_failed directly, so a client waiting on one stops as soon as it is cancelled instead of polling to its timeout and raising a confusing error — and a status added later classifies itself for clients that have never heard its name.

Confidence intervals and sensitivity as pipeline elements

LinearConfidenceInterval and SobolSensitivity are now pipeline elements you can add after a fit, returning typed results that decode client-side with no extra client code. They run as backend jobs, which is the only practical home for a Sobol analysis, and reuse the same recipes the pipeline library already ships.
Improvements
  • Drag files straight onto a project’s Raw Data table to upload them — the same gesture as a file drive — with a progress bar, a cancel, and new rows appearing at the top as they land. The upload page still works as before.
  • The raw data grid fills the viewport height instead of stopping at a fixed box.
Fixes
  • The analysis preview reads every analysis the platform writes. Previews of compressed results failed to open; they now decode in the browser.
  • A file that could not be parsed now stays failed instead of flipping back to “waiting for a cell” with an Attach button that could never succeed — and a file whose data cannot be rebuilt fails once, terminally, rather than being retried on every cell that is created.
  • Rows appear during an upload into a project that had none. The table only refreshed while something on screen was already in flight, so a first upload showed a progress bar over an empty table.
  • A measurement created from a raw file now carries its whole header — cycler, channel, operator, instrument, cell label, temperature setpoint, software version, export provenance and the test’s start time — rather than only the procedure name. Nothing downstream can recover it once the file has become a measurement, so this was the only place to write it.
  • Section detection reads its voltage window from substantial loads only. A brief pulse on a depleted cell could define the window, which collapsed a whole rate-capability record into one bogus capacity check. Pulse grouping also tolerates the cycler’s own timing jitter, so a train of 20 pulses stamped 9.000001 s no longer loses several of them.
  • Large batches of fits size their submission limits per user, so one user’s burst no longer eats the headroom of everyone sharing the platform.
  • A simulation that asks for an output it cannot produce is now refused when you submit it, naming the variable and suggesting the nearest real one, rather than completing with the column quietly missing. Note the behaviour change: such a request used to return a simulation and now returns a 400. Nothing that produced correct output changes, and a refused request creates nothing, so correcting the name and sending it again works. Separately, a variable that fails while results are assembled now costs only its own column instead of every variable requested alongside it.
Fixes
  • MSMR site fractions that did not sum to 1 were being accepted silently. Under one of the constraint methods the fit could return fractions summing to 0.885 or 1.72, which effectively rescales the electrode capacity — a fit could look excellent at ~2 mV RMSE while the parameters were unphysical. The fractions are now normalized, a post-fit check names the sum and the remedy if they still drift, and the stricter constraint method fails loudly rather than reporting a bad number.
  • An MSMR half-cell fit keeps its data’s capacity origin. The capacity column was being re-zeroed on the first point, so the model was compared against a grid shifted by whatever a cycler export happened to start at, and the discarded offset reappeared as a wrong lower excess capacity — a physical quantity that feeds downstream state-of-health calculations.
Improvements
  • raise_on_failure now covers cancellation, so a cancelled pipeline raises rather than returning as though it had finished.
Fixes
  • The extra-variables example and its field documentation asked for electrode-resolved names their model does not have, so they never produced the column they demonstrate. Both now request anode and cathode potentials, which the quick model exposes.
Improvements
  • The parameterize templates now read model-vs-data channels off the typed result object rather than assembling them by hand, and gain a section on fitting a parameter per objective — both the fixed-per-objective and the fitted-per-objective forms, which the granularity guidance previously described without showing how to express.
  • discover-api points at the typed series accessor, so an agent reading the reference before an operation finds the one-call path rather than only the raw two-call read.
Raw cycler files upload, dedupe and attach themselves to cells; automatic section detection on a test record; header metadata for every cycler format; a protocol flowchart view

Raw data: drop a folder of cycler files, get measurements

A project now has a Data → Raw Data area that takes cycler exports as they come off the machine. Drop a batch of files or a zip on the upload page and each one becomes a record that is detected, parsed and — where the file’s name says which cell it belongs to — turned into a measurement without anyone typing a cell number.The parts worth knowing about:
  • Nothing has to be right first time. Files that need a human land in a review queue with the specific finding and a choice to make, rather than failing quietly. Attaching a record to a cell is one action from the row.
  • A re-upload of the same bytes is refused before the upload starts, with a pointer to the record that already holds them. Identical content under a new name almost always means the first name was wrong, so records can now be renamed — which is the actual fix, since the cell and measurement names are read from the filename.
  • Large archives upload directly, so a multi-hundred-megabyte export no longer dies partway through.
  • A re-pulled export is a new snapshot, not an overwrite. A test that is exported again after another day of cycling keeps every earlier file exactly as it was; the snapshots group under a run so the history stays readable.
Everything in the table narrows on the server — page, status, search and sort — so a project that accumulates a file per export still shows a row count that agrees with the rows.

A test record now describes its own sections

Point the platform at a cycling record and it identifies what the test actually contains — a formation, a rate ladder, a pulse train, a stretch of cycling — and computes the headline numbers each of those is asked for, per occurrence.Several measurement conventions were tightened while this was built, and they change the numbers you get:
  • Capacity is named by direction. Charge and discharge are separate quantities and are now reported as such, with an explicit direction on every row rather than folded into a metric name. The same applies to capacity retention, which was silently a discharge-only number, and to pulse resistance, which was pooling charge and discharge pulses into one series.
  • State of charge is bounded by the cutoffs, not anchored on them. A rate ladder is built from discharges that hit the voltage floor without emptying the cell, so treating the deepest one as empty put the pulse train that followed at a negative state of charge. Loads that end on a limit now bound the count instead of defining it — no threshold, nothing to tune.

Header metadata from every cycler, not just one

Every reader now extracts what its file’s header declares — operator, schedule or procedure name, channel, start time, cell identifiers — and translates it into one shared vocabulary, so Maccor’s Procedure, Novonix’s Protocol, BaSyTec’s Testplan, Arbin’s Schedule File Name and Neware’s Step file all arrive under the same field. Previously only Maccor carried a real header through and everything else reported little more than a start time.The immediate payoff is that a measurement records the protocol it was run under at upload time, with no extra parsing step.

Protocols draw themselves

A protocol’s detail page gains a Flowchart view alongside the existing UCP, human-readable and vendor-format views. It draws the compiled protocol as a spine of step cards, with repeat loop-backs and goto jumps in their own lanes, blocks outlined with their repeat counts, and parameter references marked as tokens. Step cards and edge conditions show their full detail on hover.
Improvements
  • The lab status report can now be exported as a PDF. A Generate report button on the Lab wall opens a dialog to pick sections and tune the report’s windows, then downloads the result.
  • Filter pills on data tables are multi-select. The enum filter on every server-filtered table is now a checkbox list that stays open while you toggle, showing up to three labels before collapsing to a count.
  • Cell specifications are listed on a material’s detail page, including the component role each one uses the material in.
  • The built-in material catalog grows from 22 to 30 materials, adding Verbrugge 2017 graphite, silicon (both directions), LFP, LMO and NMC, plus two Paul 2024 graphites — LFP and LMO being chemistries the catalog previously lacked entirely. Each arrives with both its fitted MSMR parameters and the OCV curve evaluated from them.
  • A large burst of fits or optimizations no longer fails on submission. Batch jobs beyond the compute provider’s rate limit now wait as pending and submit when capacity frees up, instead of being marked failed.
  • Cell specification and instance pages render nested JSON as nested, so a nested key is visually distinct from a sibling.
Fixes
  • The pipeline element drawer now shows the configuration an element actually ran with. A datafit could not show what it was fitting, and every Calculation element rendered an empty details panel with a generic header.
  • Uploading a vendor protocol file and pressing Save failed with a message about YAML mappings — it was reading the raw vendor file rather than the converted protocol. Every vendor format was affected.
  • Selecting a right-hand y-axis variable no longer resets the plot’s zoom.
  • The pan tool stays selected after a pan, instead of the toolbar switching itself back to zoom.
  • Tables on the cell specification page fill the viewport height instead of stopping at a fixed box.
  • The two shipped system optimization templates could not be edited — the write path rejected the very form they ship with.
Improvements
  • The typed result object gains a series accessor giving the full-resolution model-vs-data channels per objective, alongside the decimated overlay used for figures.
Fixes
  • Long array fits no longer run out of memory partway through.
  • A Validation keyed by a number (a temperature, a C-rate) emitted a configuration its own reload path rejected.
  • A fit whose every evaluation failed is reliably reported as failed rather than depending on the cost it reported.
  • A composite stoichiometry window now requires its usable capacity at validation time rather than failing later at runtime.
Improvements
  • client.material_property_dataset.to_prior(...) reads a scalar from a material property dataset and returns a prior centred on it, ready to drop into a fit. Width is supplied explicitly as either an absolute or a fractional standard deviation, with a lognormal option for strictly positive parameters spanning orders of magnitude.
Fixes
  • 33 schema classes that their packages defined but never exported are now importable — every *Options companion was affected. A test now enforces that in both directions, so it cannot regress.
  • Fits whose posterior chains were too large to inline now work with marginal(), credible_interval() and .x, which previously raised or returned nothing on exactly those fits.
Improvements
  • Maccor exports reporting milli-units (Current (mA), Capacity (mAHr)) now read, with the scale applied on read. Previously they could not be read at all, and the obvious workaround — remapping the column name — produced values a thousand times too large with no warning. The cycler’s own DCIR column is carried through too.
  • The Maccor reader now carries the mode, end status, loop and register columns the cycler writes about its own execution. The mode column is the only thing distinguishing step-transition markers from genuine rest samples, and the register columns often hold the per-cell capacity a procedure used as its C-rate basis.
  • The CSV reader tolerates a metadata preamble above the header and ragged rows below it — a trailing delimiter on every data row no longer aborts the parse.
Improvements
  • DeltaSOC is now a first-class end condition. A protocol ending a step on a change in state of charge previously had that limit dropped silently, leaving an unbounded step that surfaced much later as an opaque “each step must have at least one termination condition” error. Because it stays relative, it resolves against whichever cell the protocol runs against rather than the one it was authored on.
  • Cell capacity is prefilled from the protocol file’s header where the file declares it, so a protocol’s C-rate steps resolve against the right cell instead of a 1 Ah placeholder. Units are read from the file rather than assumed.
Fixes
  • Three operator and end-type rules now warn instead of rejecting the protocol. A protocol imported from a real cycler file may legitimately contain any of them, so blocking was too strong. Validation and parse both report their findings, so nothing is lost by not blocking.