Changelog — ionworks-api¶
All notable changes to this package are documented here. The format is based on Keep a Changelog, and this package follows Semantic Versioning.
For platform-wide release notes (Studio, pipeline, SDK, and more), see docs.ionworks.com/changelog.
[0.40.0] - 2026-11-04¶
Added¶
parameterized_model.get()andsimulation.get()takesummary=Trueto leave out parameter values and simulation data (#2694)A design parameter can be a
ParameterTable({x, y, interpolator}) for a function-valued parameter, inclient.simulation.protocol()and inprotocol_batch()conditions (#2689)client.parameterized_model.get_parameter_values()takesnamesandmatchto return only some parameters (#2689)Parameterized-model create, update and version writes accept
summary=Trueto return metadata without parameter values or model configuration (#2688)client.pipeline.list_elements()lists a pipeline’s elements with their config and result (summary=Truereturns metadata only),get_element_job_config()returns one element’s full config, andclient.pipeline.get()returnsproject_id(#2688)client.simulation.get_steps()downloads a completed run’s step summary without its time series (#2688)client.parameterized_model.get_parameter_values(resolve=False)returns calculated parameters as calculations, to copy into another model (#2688)client.parameterized_model.create_version()saves a new version of a model with some parameters changed, andlist_versions()lists a model’s versions (#2688)
Fixed¶
A cell specification’s
urlopens its page under Cells, and a cell instance’s opens its page under its specification, instead of the old data-section routes (#2677)
[0.39.0] - 2026-11-02¶
Breaking changes¶
Project records carry your own
my_roleandmy_permissionsinstead ofuser_project_roles, every member’s role with all its permissions;client.organization.members()lists who is in which project (#2546)
Added¶
client.simulation.protocol()andprotocol_batch()takesimulation_settings, numerics for those runs only:solver,var_pts,submesh_typesandspatial_methods(#2580)Per-run
simulation_settingsalso takediscretisation_kwargs(#2598)client.protocol_groupmanages protocol groups (ProtocolGroup), and protocols takeprotocol_group_idon create, update and list;Noneon update removes a protocol from its group (#2551)client.metric_suitetrains Gaussian-process surrogates of a metric suite’s KPIs and predicts from them:create_surrogate,wait_for_surrogate,predictand related methods (#2512)Records fetched by id carry
url, their page in the web app, andapi_url, their API endpoint (#2587)Sites carry an IANA
timezone, defaulting toAmerica/New_York(#2639)client.cell_measurement.create()adds the cycle-cumulative capacity and energy columns (Cycle discharge capacity [A.h]and the like) to a time series that has the per-step columns but not these, before uploading it; columns you supply are kept (#2636)
Changed¶
Requires
polars>=2.1.0, up frompolars>=1.43.0(#2657)
[0.38.0] - 2026-10-23¶
Added¶
client.model_buildermanages recipes that turn a cell specification into a model’s parameters: check a cell spec against one, preview a mapping,dry_runit, and build or save a parameterized model (#2111)client.model.create_from_zoo(name, cell_spec_id=...)uploads a PyBaMM model-zoo model and creates its parameterized model in one call (#2485)client.parameterized_model.create(None, data)creates a parameterized model with no cell spec, in a project;parametersalso accepts apybamm.ParameterValuesor a parameter-set name (#2485)client.simulation.list()takesprotocol_id,state(queued,running,completedorfailed),summary,limitandoffset;protocol_idcombines withparameterized_model_idorstudy_id, and withlimitoroffsetit returns aPaginatedListcarrying.total(#2425)Simulation records carry
protocol_idandprotocol_name(#2425)SimulationResponse.already_existedis True when an identical run, finished or still running, was returned instead of starting a new one;SimulationResponse.protocol_idis the saved protocol the run used (#2425)client.parameterized_model.list_by_project(summary=True)lists models without their parameter values (#2425)
Changed¶
Models belong to a project:
client.model.list()lists the client’s project unless givenproject_id=, andcreateandupload_customdefault to the client’s project (#2332)client.search.query(project_id=...)also restricts parameterized models, protocols and cell data to that project, keeping rows with no project; before, it narrowed only studies, optimizations and pipelines (#2425)client.protocol.convert(..., target="biologic_bttest")needsnominal_capacity_ahwhen the protocol uses C-rate steps or cutoffs, asnewaredoes: BioLogic C-rates are now written as absolute currents (#2542)
Fixed¶
Large uploads no longer fail when throughput to storage is low: multipart uploads send 16 MiB parts two at a time, and a part that times out is retried (#2468)
[0.37.1] - 2026-10-20¶
Changed¶
client.pipeline.createrefuses a pipeline whoseDirectEntryreads a pipeline (pipeline_id) or cell specification (cell_spec_id) from another project, with a 403 naming the element. Previously such a reference was accepted. Create the pipeline in the source’s project, or enter the values directly.Requires
pandas>=2.2.2andpyarrow>=16.0.0. Earlier releases do not import alongside numpy 2.
[0.37.0] - 2026-10-09¶
Breaking changes¶
Cell instances no longer have a free-text
batchfield. Manufacturing lots are now their own records, and an instance points at one throughbatch_id.client.cell_instance.create(),create_or_get()andupdate()raise aValueErrornaming the replacement ifdatacontainsbatch. To migrate, create or look up the lot withclient.cell_batch.create_or_get(cell_spec_id, {"name": ...})and passbatch_id=<lot>.id.Simulation configs are checked for unknown keys.
client.simulation.protocol()andprotocol_batch()raise aValueErrornaming any misspelt or misplaced key, where it was previously ignored and the simulation ran without it.
Added¶
client.cell_batchmanages cell batches (manufacturing lots of one cell specification):list(),get(),create(),create_or_get(),update()anddelete(). Deleting a batch unlinks its cells and never deletes them. The new modelCellBatchis exported fromionworks.client.cell_instance.list(..., batch_id=...)returns only the cells in one batch. Instances carrybatch_idand a read-onlybatch_name.Measurement tags.
CellMeasurement.tagsholds a measurement’s tags;client.cell_measurement.list_tags(project_id)lists the tags a project uses with their counts;add_tags()andremove_tags()change tags on up to 1000 measurements at once; andlist()and the newlist_by_project()filter bytags_all/tags_any. The new modelMeasurementTagUsageis exported fromionworks.client.simulation.protocol()andprotocol_batch()acceptprotocol_idto run a saved protocol, in place ofprotocol_experiment.project_idthen defaults to the protocol’s own project.client.simulation.protocol_batch()acceptsconditions, an explicit list of runs each with its ownexperiment_parametersanddesign_parameters, as an alternative todesign_parameters_doe.client.simulation.get_statuses(simulation_ids)returns the status of many simulations in one request.client.cell_measurement.time_series(..., row_range=(start, stop))downloads only the rows in that window.client.simulation.delete(simulation_id)andclient.parameterized_model.delete(cell_spec_id, parameterized_model_id).
Changed¶
A pipeline data fit’s result carries its best cost, so
fit.costis set whereSimplePipelineusers previously readresult["cost"].
Deprecated¶
Every
client.simple_pipelinemethod emits aDeprecationWarningnaming itsclient.pipelineequivalent. SimplePipeline will be removed no earlier than November 2026, and past runs cannot be fetched after that.
[0.36.0] - 2026-09-30¶
Added¶
Organization membership management on
client.organization:members(),get_member(email),invite(email, role="Member"),set_role(user_id, role),deactivate(user_id),reactivate(user_id),resend_invite(user_id)andremove(user_id). The new modelsOrganizationMember,ProjectMembershipandInviteResultare exported fromionworks.Project membership management on
client.project:roles(),add_member(project_id, user_id, role=...),invite_member(project_id, email, role=...),update_member(project_id, user_id, role)andremove_member(project_id, user_id).roleis a project role name (case-insensitive) or id. The new modelProjectRoleInfois exported fromionworks.client.analysis.create(..., plots=[...])saves plot presets, which the web app offers as views of the analysis table.Analysis.plotsreturns them, andupdate()acceptsplots.
Changed¶
ProtocolSimulationBatchRequest.max_backward_jumpsdocuments the server default of 1000 when it is left unset.
[0.35.0] - 2026-09-29¶
Deprecated¶
client.job.create()now emits aDeprecationWarning. The server no longer accepts direct job submissions and answers with a 410 error. Start work throughclient.pipeline,client.simple_pipeline,client.simulationorclient.ecm.get,listandcancelare unaffected.
Changed¶
Raised the
pybammlower bound to>=26.9.0.0, and theboto3lower bound in thelarge-uploadsextra to>=1.43.98.
[0.34.0] - 2026-09-24¶
Added¶
client.analysis.find_one(measurement_id, analysis_id=..., analysis_type=..., name=...)returns the single analysis on a measurement matching every field given. It raises when no analysis or more than one matches, listing the candidates so the right selector can be copied.
Changed¶
client.simulation.get_result()downloads the time series and steps as parquet rather than one JSON body. It returns the sameSimulationResultshape as before. A 404 can now also mean an older result that has not yet been converted; retry after a moment.
Fixed¶
Files at or above 32 MiB now prefer S3 multipart uploads when
ionworks-api[large-uploads]is installed. If a signed upload receives a storage-edge timeout, the client makes one multipart attempt from the same file position.
[0.33.0] - 2026-09-22¶
Changed¶
App URLs built by
client.urlsno longer carry the/dashboardprefix: a project route is now/projects/{project_id}/.... The old URLs redirect, but anything comparing against a hardcoded/dashboard/...string needs updating.
Fixed¶
An
extra_variablesname the model does not carry is refused when the simulation is submitted, rather than failing later during the run.
[0.32.0] - 2026-09-14¶
Changed¶
client.pipeline.wait_for_completion()andclient.simple_pipeline.wait_for_completion()now raiseIonworksErroron a cancelled pipeline as well as a failed one whenraise_on_failure=True(the default). The status is carried into the message (Pipeline <id> canceled). Passraise_on_failure=Falseto get the record back instead, as before.PipelineSubmissionResponseandSimplePipelineSubmissionResponsecarry server-derivedis_terminalandis_failedflags, so the client no longer decides which statuses are terminal. A status this SDK has never heard of (added server-side later) is classified correctly without an SDK upgrade. Both fields are required, so this version needs a backend that publishes them.
Fixed¶
client.pipeline.wait_for_completion()stopped polling only oncompletedorfailed, so a cancelled pipeline kept polling untiltimeoutelapsed and then raisedTimeoutError. It now returns (or raises, see above) as soon as the pipeline is cancelled.
[0.31.0] - 2026-09-05¶
Added¶
client.material_property_dataset.to_prior()centres a fit prior on a scalar already stored in a property dataset, so a measured value feeds a fit without being retyped as a literal:prior = client.material_property_dataset.to_prior( dataset.id, column="particle radius", parameter_name="Negative particle radius [m]", rel_std=0.1, ) fit = iws.DataFit(objectives=..., priors={prior.name: prior})
A scalar carries no spread, so exactly one of
stdorrel_stdis required.distribution="lognormal"suits a strictly positive parameter spanning orders of magnitude, such as a diffusivity or conductivity.ParsedProtocol.nominal_capacity_ahreports the cell rating declared in a protocol file’s header, when the file carries one.
[0.30.0] - 2026-08-31¶
Added¶
Pipeline results decode into the typed result objects from
ionworks-schema, so a fitted parameter or a figure is reachable directly off the result rather than by fetching job metadata and parameter traces by hand:result = client.pipeline.result(pipeline_id) fit = result.element("fit") fit.parameter_values["Positive particle diffusivity [m2.s-1]"] fit.plot_fit_results() fit.plot_trace()
PipelineResponse.element(name)and.resultsexpose the typed objects, andSimplePipelinegainsresult_object. This is additive: the raw.resultand.element_resultspayloads are unchanged.result.element(name).seriesreturns the full-resolution per-objective model-vs-data channels,{objective: {channel: [values]}}, for data-fit and validation elements. Use.overlayfor the decimated data behind figures and.serieswhen you want the raw numbers to save or analyse.Plotting from a result object needs matplotlib, which is not installed by default:
pip install 'ionworks-schema[plot]'.
Changed¶
Requires pybamm 26.8.0.0 or newer.
[0.29.0] - 2026-08-25¶
Added¶
client.cell_measurement.extend(measurement_id, time_series)appends a delta time series to an unfinished measurement — one whoseend_timeis not yet set — so a running test can be uploaded incrementally instead of re-sending the whole series. Pass only the new rows: theirTime [s]must start after the last existing sample and the column set must match the existing series exactly. Steps and cycles are recomputed server-side from the stitched result, so never pass steps. The call waits for that processing by default; passwait_for_processing=Falseto return as soon as the upload is confirmed.Uploads larger than 512 MiB now use S3 multipart, making multi-gigabyte raw files and time series upload reliably. This needs an optional dependency: install it with
pip install 'ionworks-api[large-uploads]'. Without the extra, files up to 1 GiB still upload via the existing single request; above that the extra is required.client.raw_data.create()accepts atimeout, as a(connect, read)pair or a single value for both. On the multipart path the timeout applies per part rather than to the whole transfer.Measurements carry a
protocol_id, referencing the protocol a run executed. Set it throughcell_measurement.create()orupdate()like any other field. The protocol must belong to the measurement’s own project. It is preferred over the free-formprotocoldict, which stays available for imported data with no executable protocol behind it; setting both records what the run was meant to execute plus the conditions it actually ran under.client.pipelinegainedupdate(),cancel()anddelete(), matchingclient.simple_pipeline. Previously a pipeline submitted throughclient.pipelinecould not be renamed, cancelled or removed from Python at all, even though the API supported all three.client.pipeline.list()accepts the full filter set the endpoint supports —id,name,description,status,created_by_email,created_at,updated_at, the_gt/_ltvariants,order_by,orderandoffset— rather than onlyproject_idandlimit.
Changed¶
job.get_plot_data()accepts up to 80000 points per trace, raised from 10000, so a long run can be fetched at full resolution in one call. The default is unchanged at 2000.Both
client.pipeline.list()andclient.simple_pipeline.list()now returnPaginatedList, so the two clients agree. It behaves as a list (iteration, indexing,len(), truthiness) and carries.items,.countand.total, so loops and the three attributes keep working unchanged.Behaviour change:
client.simple_pipeline.list()previously returned a Pydantic model, so pydantic-only methods on the result —model_dump(),model_dump_json()— no longer exist. Use.itemsand serialise those. The underlyingSimplePipelineListResponseclass is also gone; it was never exported fromionworks, so only code importing it from the submodule directly is affected.client.pipeline.list()gains.total, which it previously discarded.
[0.28.0] - 2026-08-18¶
Added¶
client.channel.update()accepts aservice_scheduled_untildatetime, recording when a booked outage is expected to end (must be afterservice_scheduled_at).client.channel.list_incidents()reads back a channel’s out-of-service history, newest first, including whether the current outage is overdue to return.client.protocol.convert()acceptsverify=Trueto ask the server to round-trip the emitted file through its parser and reject the conversion if the protocol no longer means the same thing (a dropped loop count, goto, or safety bound). Reliable today forbiologic_bttestandnovonix; the other writers still report benign artifacts as differences.New validator
validate_charge_discharge_column_directiondetects a cycler export with the charge/discharge capacity (or energy) column labels inverted, which is otherwise invisible to every cumulative-reset and magnitude check.client.protocol.convert()accepts"arbin_sdx"as atarget, writing the Arbin MITS Pro 8+.sdxdialect alongside the existing MITS Pro ≤7.sduwriter ("arbin", unchanged and not deprecated).
Fixed¶
client.cell_specification.list(name_exact=...)(and the internal lookupcreate_or_getfalls back to) is now project-scoped, matching spec names being unique per project rather than per organization — an org-wide exact match could previously return a different project’s spec or misreport a locally-unique name as ambiguous.validate_charge_discharge_column_direction’s same-sign-current check no longer discards a step’s vote when a single boundary sample inherited from the preceding step pollutes its min/max.
[0.27.0] - 2026-08-11¶
Breaking changes¶
client.material.list()is now project-scoped: it returns only the materials in one project, and raisesValueErrorwhen noproject_idis given and the client has no default. Previously it listed materials across the whole organization, andproject_idonly scoped each material’sproperty_count. Passproject_id=explicitly, or set a client-wide default (viaIONWORKS_PROJECT_ID), and expect a narrower result set than before.
Added¶
Write methods on
client.material_property_dataset:create()uploads a DataFrame (serialised to parquet, inferringcolumnsfrom a trailingname [unit]header when not given),replace_file()swaps the stored file,update()patches metadata, anddelete()removes a dataset.get_download_url(kind="parquet"|"original")returns a signed URL.replace_file()does not infer columns, so it cannot erase stored units: whencolumnsis omitted it checks that the replacement’s layout matches the stored specs and raisesValueErroron a mismatch rather than mislabelling the data.Server-side filtering, ordering, and pagination on
client.material.list():name,manufacturer,product_id,created_at/updated_at(plus_gt/_ltrange bounds),order_by, andorder. Text filters take a bare value for an exact match or an operator prefix such as"ilike.%graphite%"for a partial one;name_exact=is shorthand for exact equality and cannot be combined withname.An
ionworksconsole script for managing the Agentic Toolkit:ionworks skills install(aliased asupdate) downloads the toolkit and installs it for your agents, removing a previous install so retired skills do not linger, andionworks skills listshows what is installed. Both take--globalto target the user-level directory instead of the current project, and--agentto name target agents explicitly instead of auto-detecting.
[0.26.0] - 2026-08-10¶
Added¶
Material reverse lookup on
cell_spec.list(...):material_idreturns the specs referencing a material through any component slot, and accepts a list to match any of several materials. Per-slotanode_material_id,cathode_material_id,electrolyte_material_id,separator_material_id, andcase_material_idrestrict the search to one slot, andexclude_cell_spec_iddrops a spec from the results. A reverse lookup is project-scoped, so it needs aproject_id(falling back to the client’s, orIONWORKS_PROJECT_ID). Filtering happens in the database, sototalcounts every matching spec rather than the rows in the page.cell_spec.related_specs(cell_spec_id, ...)returns the other specs that share a component material with a given spec. By default any of its slot materials matches in any slot; passslots=["anode", "cathode"]to compare each named slot only against the same slot on the source spec.exclude_self(default True) andinclude_componentscontrol self-exclusion and whether nested component and material data comes back.client.planned_measurements.auto_schedule_proposal(...)proposes the earliest channel reservations for a list of requested tests, in priority order. The search is unbounded in time, so each request gets the earliest start that actually fits; an optionalstart_afterdefers the whole batch when an operator cannot begin immediately. The result is transient — nothing is reserved until it is applied.client.planned_measurements.apply_auto_schedule_proposal(...)commits the assignments you selected from a reviewed proposal. The API re-checks each one against its proposal-time version and current channel availability, and on a stale or conflicting proposal rolls back the whole batch and raisesIonworksErrorwitherror_code == "SCHEDULE_STALE"— generate a fresh proposal and retry.AutoScheduleProposalandAutoScheduleAssignmentmodels, exported from the top-levelionworksnamespace.AutoScheduleAssignment.is_scheduledtells you whether an assignment is complete and safe to apply; incomplete ones carry anunscheduled_reasonexplaining that no channel in the project can take the test.
[0.25.0] - 2026-08-06¶
Added¶
client.search.query(...)runs one query across every entity type in the organization — projects, models, cell specifications and instances, measurements, parameterized models, templates, materials, studies, optimizations, and pipelines — returning rankedSearchResultrecords in aSearchResponse. Name fields match on case-insensitive substring and free-form text on prefix full-text search, with substring matches ranked first.per_typekeeps one entity type from crowding out the rest, andentity_types/project_idnarrow the sweep; search spans the whole organization by default rather than the client’sproject_id.client.cyclertracks hardware service:list_service_events,start_service, andcomplete_service, plus theCyclerServiceEventmodel. Starting service opens an event and an incident on every channel so the whole instrument reads as down; channels already out of service keep their own more specific incident and stay out when the service completes.client.protocolnow covers the whole protocol lifecycle rather than validation and conversion alone:Saved protocols —
list,get,find_by_name,create,create_or_get,update,delete, plushuman_readableandsource_protocolrenderings. Protocols are project-scoped and content-addressed, so saving one that already exists returns the existing record instead of a duplicate.parse_file— turn a vendor cycler protocol file (Maccor, Arbin, Neware, Novonix, BioLogic, …) into UCP, reporting any drive cycles or subroutines the file referenced but did not carry.
New models:
ProtocolandParsedProtocol, exported from the package root (from ionworks import Protocol, ParsedProtocol).protocol.listgainedname/name_exact/created_by_email/created_after/created_before/updated_after/updated_before/order_by/order, matching the other list clients. Filtering, ordering and pagination are applied by the database, sototalcounts every matching protocol rather than the rows in the page.protocol.find_by_namenow matches server-side. It previously scanned an unpaginated listing, so it returnedNonefor any protocol past the server’s row cap. It also raisesValueErrorwhen several protocols in the project share the name — protocols are deduplicated on their body, not their name, so returning an arbitrary match could silently simulate the wrong one.
Changed¶
Protocol responses no longer carry
access_level. Every protocol reachable through the API is project-scoped, so the field could only ever read"project".
Fixed¶
simulation.protocolnow sends the resolvedproject_idto the batch endpoint, so a run that builds a quick model succeeds instead of being rejected for having no project to own the parameterized model. Theproject_idis resolved as before — from the config, the client, orIONWORKS_PROJECT_ID— so no call site has to change.
[0.24.1] - 2026-08-05¶
Fixed¶
jobs.get_posterior_samplesdocumented a narrower contract than it has. Every sampler populates the sample keys, not only Bayesian ones; it is fits driven by a conventional optimizer (CMAES,ScipyMinimize), along with optimization and validation jobs, that return an empty dict. The docstring now also states thatsamplesvalues are nested(starts, iterations)for a multistart fit and a flat per-iteration list for a single start — so index the iteration axis last ([..., burnin:]) to handle both — thatsample_costsis shaped like one parameter’s chain, and thatsample_burninisNonefor samplers with no burn-in concept (GridSearch,PointEstimateSampler). Behaviour is unchanged.
[0.24.0] - 2026-08-03¶
Added¶
protocols.convertacceptsnominal_capacity_ah, the rated cell capacity in amp-hours. It is required for thenewaretarget when the protocol uses C-rate steps or cutoffs, because Neware sets current in absolute mA and has no C-rate mode. Other targets express C-rate natively and ignore it.
Changed¶
Raised the
requestslower bound to>=2.34.2.
Fixed¶
jobs.get_plot_datanow callsGET /pipelines/datafits/{job_id}/plot_data. The previous unprefixed path returned a 404, so fetching model-vs-data plot traces for a data-fit job failed.
[0.23.0] - 2026-07-29¶
Added¶
ProtocolSimulationBatchRequestaccepts aproject_id. Parsed protocols are created as project-scoped experiment templates, so the backend now requires the project. When omitted, it falls back to theproject_idconfigured on theIonworksclient (or theIONWORKS_PROJECT_IDenvironment variable).
[0.22.0] - 2026-07-28¶
Breaking changes¶
channel.createno longer acceptsout_of_commissionand rejects it withBAD_REQUEST: a channel is always commissioned in service. Usechannel.updateto take one out of service afterwards, which records the outage in the channel’s incident history.
Added¶
Channel outage history. Passing
out_of_commissiontochannel.updatenow records an incident, and may be accompanied byincident_category(one ofhardware_failure,maintenance,calibration,decommissioned,other; defaults toother) andincident_noteswhen taking a channel out of service, orresolution_noteswhen returning it. Re-sending the value a channel already has is a no-op rather than a new outage.MeasurementProcessingError, raised when the server cannot process an uploadedtime_seriesmeasurement. Itsfailuresattribute maps each affected measurement id to the reason, so a batch can report several at once.cell_measurement.wait_for_processing, plus await_for_processingargument (defaultTrue) on the upload methods, so an upload no longer returns a measurement that looks created but holds no usable steps.
Changed¶
channel.updatenow also raisesCONFLICTwhen a channel’s service state was changed concurrently; re-read the channel and retry.
[0.21.0] - 2026-07-24¶
Added¶
simulation_settingssupport (a persistent bag of pybamm mesh and solver settings) on the simulation, study, and parameterized-model create/update paths.
Changed¶
Aligned
SimplePipeline.createwithPipelineand wrapped datafitplot_data.
[0.20.0] - 2026-07-22¶
Added¶
New
planned_measurementclient for requesting, scheduling, and cancelling future lab measurements, with a matching skill (#1292). A planned measurement requires a named protocol (protocol_id) and a cell specification.channel.watchto follow the live test running on a channel, and an org-widechannel.list_allplus channel/measurement detail helpers.cell_specification_nameonLabMeasurementSummaryso lab measurement listings can show the cell spec without a second lookup.Source tracking for material-property datasets and analyses: created records now carry their originating source (#1276).
Fixed¶
List endpoints now honour the filters the SDK already sends, so server-side narrowing is applied instead of being silently dropped (#1337).
[0.19.0] - 2026-07-20¶
Added¶
New
labclient for answering equipment / occupancy questions: lab status, utilization, free and stale channels, and which measurement is on a channel (#1262, #1274).JobClient.get_posterior_samplesto retrieve MCMC posterior sample chains from Bayesian sampler datafit job metadata (#1227).validate_measurement_timingwarning-severity checks for measurementstart_time/end_time(future timestamps, end-before-start, and wall-clock vs data duration mismatch) (#1246).
Changed¶
Raised the
pydanticdependency floor from>=2.12.5to>=2.13.4(#1284).
Fixed¶
Measurement artifact cache TTL is now evaluated per file, not per directory, so a fresh write no longer resurrects an expired sibling artifact (#1265).
[0.18.0] - 2026-07-16¶
Added¶
New
site,cycler, andchannelclients for managing test equipment: create, list, retrieve, update, and delete sites, cyclers, and their channels. Cell measurements can now be linked to a channel via achannel_idfield (#1163).
[0.17.0] - 2026-07-14¶
Changed¶
Raw-data uploads now use a three-step signed-URL flow (
initiate-upload→ directPUTto storage →confirm-upload) instead of multipart form uploads; the file body no longer passes through the API server, so large raw cycler files upload more reliably. The content type is derived from the filename (#1204).
[0.16.0] - 2026-07-14¶
Added¶
New
analysisclient for creating, listing, and retrieving measurement-scoped analyses, with results returned as dataframes (#1171).Organization- and project-scoped raw data storage: a new
raw_dataclient for uploading, listing, and downloading raw cycler files, plus supporting additions oncell_measurement(#1179).Submitted pipelines now accept
file:andfolder:references to raw data, validated client-side before submission (#1040).
[0.15.1] - 2026-07-13¶
Changed¶
Internal: model enums now subclass
StrEnuminstead of(str, Enum); runtime string values are unchanged (#1174).
[0.15.0] - 2026-07-10¶
Added¶
client.organization.usage()returns the organization’s usage and limits for the current calendar-month period (resetting on the 1st). Simulation exposes.usage/.limitand compute adds a per-job-type.usage_by_typebreakdown; all values are in hours and aNonelimit means that type is unconstrained (#1117).EIS measurement upload validation: checks the
Z_Imsign convention and impedance magnitude consistency before upload (#1133).
[0.14.0] - 2026-07-07¶
Breaking changes¶
ECM
FitResults.capacity_AhandValidationResults.capacity_Ahare nowlist[float](one entry per measurement segment) instead of a singlefloat. Callers readingcapacity_Ahmust index the list (validation results are a single-element list) (#1081).
Added¶
ECM fits accept a per-measurement
capacity(all-or-none across measurements) and aregularizationsmoothness prior on the R0/RC parameter curves;submit_fit_from_filegains aregularizationargument (#1081).
Fixed¶
Corrected the
cell_spec.createexample in the cell-specifications user guide to match the API model (#835).
[0.13.0] - 2026-06-30¶
Added¶
Pipeline configs now accept
element_type: "array_data_fit"for fits that run independently at each value of an independent variable (e.g. diffusivity vs. stoichiometry, parameter vs. temperature). Configurable with the same fields asdata_fit; see the newexamples/pipeline/array_datafit.pyexample.client.resolve_measurement(cell_specification, cell_instance, measurement)— resolve a measurement from human-readable names, walking the spec -> instance -> measurement hierarchy (each level filtered server-side by exact name). Returns theCellMeasurement; raisesIonworksError(404) when a level has no match, or (409) when a name is ambiguous within its parent.
[0.12.0] - 2026-06-10¶
Breaking changes¶
OptimizationClientis decoupled from the jobs API (#861). Optimizations are now first-class resources under/optimizationsrather than/optimize.get/wait_for_completionreturn the flat optimization resource (with a top-levelstatus) instead of a{"optimization": ..., "job": ...}dict,listreturns{"optimizations": [...], "total": n}(nojobskey), and the terminal states are renamedcompleted/cancelled→succeeded/canceled. Migration: readresult["status"]andresult["error"]directly, and update any status checks to the new state names.
Added¶
SDK support for background-job ECM parameterization (#562).
JobClient.get_parameter_traceaccessor for retrieving the parameter trace of a job (#815).Project-scoped parameterized model listing on the parameterized model client (#806).
Fixed¶
Corrected CC-discharge step mislabeling and an unsigned mixed-mode current sign error in data processing (#848).
[0.11.0] - 2026-06-05¶
Added¶
New
SimulationResultclass (exported from the package root) — a typed result returned bySimulationClient.get_resultexposingtime_seriesandstepsas DataFrames in the active backend (polars by default, pandas when configured) (#741).
Fixed¶
Minor
Navigatordocumentation fix (#770).
[0.10.3] - 2026-06-01¶
Added¶
New
Navigatorclass (exported from the package root) — a cached, in-memory view over the cell spec → instance → measurement hierarchy that memoises list/fetch calls and returns name-sorted listings for deterministic iteration (#667).
Changed¶
Switched the
polarsdependency frompolars-lts-cputo the standardpolarsdistribution (#768).
[0.10.2] - 2026-05-29¶
Changed¶
Relaxed the
numpydependency bound to allownumpy>=2(#754).
Removed¶
Dropped unused runtime dependencies
python-dotenv,supabase, andiwutil(#752).
[0.10.1] - 2026-05-28¶
Added¶
SimplePipelinesubmission now accepts runtime options (e.g. solver settings) that are forwarded to the pipeline worker, giving callers finer-grained control over execution without changing the pipeline configuration (#708).
[0.10.0] - 2026-05-27¶
Added¶
MaterialClient(client.material) for listing and retrieving materials.MaterialPropertyDatasetClient(client.material_property_dataset) for listing, retrieving, and downloading tabular physical property datasets (e.g. conductivity, diffusivity, transference number vs. concentration).New public models:
Material,MaterialPropertyDataset,ColumnSpec.Measurement validators now cross-check the
capacityandenergycolumns against the integrals of current and power, catching unit and sign-convention errors that previously slipped through (#687).client.whoami()returns the user profile that the configured API key resolves to — the recommended way to debug credential issues and confirm which organization the SDK is authorized as (#626).
Fixed¶
Measurement validators now accept parquet files alongside the existing supported formats (#678).
Sign-convention vote is weighted by
|I| * dtinstead of row count, so short high-current segments are not drowned out by long rest periods (#682).The SDK no longer implicitly loads a
.envfile on import. SetIONWORKS_API_KEYin your environment (or pass it explicitly toIonworks(...)) before constructing the client (#630).JSON serialization now handles
datetimeand pandasTimestampvalues in request payloads so pandas-derived metadata can be passed directly without manual conversion (#720).
[0.9.0] - 2026-05-14¶
Added¶
SimplePipelineClientandionworks.simple_pipelinemodule: a lightweight client for running the new SimplePipeline workflow, exposed on the top-levelIonworksclient (#585).
[0.8.0] - 2026-05-13¶
Added¶
client.ecmsub-client for ECM (Equivalent Circuit Model) parameterization. Supports three input modes —fit_from_example(synchronous demo),fit_from_file(uploads a local cycler file), andfit_from_measurements(fits measurements already stored in the platform). Authenticated fits run as background jobs; useclient.ecm.wait_for_completion(job)to block until ready.New public models exported from
ionworks:EcmFitJob,FitResults,RcPairFit,SaveToProjectResponse.Multi-measurement fits with per-segment SoC seeds:
fit_from_measurementsaccepts ameasurements: listwhere each entry can carry its ownstart_step,end_step, andinitial_soc.Capacity co-fitting from an OCV(SoC) curve:
ecm_optionsnow acceptsocv_soc_curve: {soc, ocv}and optionalbounds_capacity: {lo, hi}; the SDK validates curve monotonicity, SoC range, length parity, and bounds inversion locally before the request hits the wire.Knot-resolution controls on
ecm_options:num_knots,num_knots_r0,knot_schedule,clamp_boundary_knots,clamp_max_ratio.Ionworks.post_multiparthelper on the HTTP client for endpoints that accept optional multipart file uploads alongside query params.JobClient.get_metadata(job_id)— fetch the parsed JSON contents of a job’s metadata blob (large fields stripped fromjob.resultand persisted to storage, e.g.validation_resultsandvalidation_plot_config). API-key clients couldn’t previously reach these fields because the path through Supabase signed URLs requires a Supabase JWT (#515).PipelineClient.get_element_metadata(pipeline_id, element_name, elements=None)— convenience wrapper that resolves an element by name to its job and returns the metadata blob. Pass a pre-fetchedelementslist to avoid re-fetching when pulling metadata for several elements of the same pipeline (#515).
[0.7.0] - 2026-05-11¶
Added¶
/protocols/convertendpoint and client helper to convert a UCP protocol into vendor-specific cycler protocol files (#578).Auto-detect
IONWORKS_PROJECT_IDfrom the environment so callers don’t have to pass it explicitly (#536).
Changed¶
Validation errors now carry a structured
ValidationIssuelist with stableCheckNameenum,severity,message, andpayload. Callers should branch one.has_check(CheckName.X)instead of substring-matching error messages (#544).
[0.6.0] - 2026-05-04¶
Added¶
skip_checksparameter on validation entry points so callers with least-privileged API keys can opt out of project/permission checks while keeping schema validation (#534).Helpers on the client for uploading and managing custom PyBaMM models (#566).
Changed¶
UCP input is now backed by a machine-checkable JSON Schema, with parser parity tests ensuring the Python parser and schema agree (#494).