Skip to content
heliaAOT
API Reference
HELIA HUB

Compatibility and versioning

heliaAOT follows semantic versioning from 1.0.0. This page says which parts of heliaAOT the version number covers. A part that is not listed under What a release promises can change in any release.

The promise starts at 1.0.0. A 0.x release is not bound by it: any 0.x release can change a promised surface, and Changes before 1.0 lists the changes that affect a configuration or a program written for an earlier one.

Within one major version, each surface below keeps working as its reference page describes it.

  • Most of those pages are rendered from a record exported from the code, named in the last column, and a test fails when a committed record no longer matches what the code exports.
  • Some records are partly written by hand, such as the operator restrictions, and the plan and report rule is written on a page rather than exported.
Surface What is promised Described by
Command line Command names, flags, accepted values and exit codes Command line (cli.json)
Configuration file Keys, accepted values and defaults, and that an unknown key, an operator attribute the operator does not take, or an invalid attribute value is an error Configuration (config-schema.json)
Python API The symbols listed in the API manifest, each at the one import path listed for it, except those it lists as provisional Python API (repo_tools/api_manifest.json)
Typed errors The HeliaAotError classes, the standard-library type each one also is, and the exit code each class declares Errors (errors.json)
Generated module The cmake, zephyr and nsx module types and their build manifests; the names of the other files module-layout.json marks public: the integration headers <prefix>_model.h, <prefix>_context.h, <prefix>_tensors.h, <prefix>_platform.h and <prefix>_test_case.h, and <prefix>_plan.json, <prefix>_report.json and <prefix>_residency.json; the declarations it marks public, the init and run signatures and their status codes; see the generated C API Generated module (module-layout.json)
Machine-readable files What Machine-readable files says for each one: the schema_version rule for the plan and the report, and only that the residency report is written Plans and reports (plan-schema.json, report-schema.json) and Generated module (residency-example.json, residency-example-placed.json)
Targets Registered platform names, matched in any case Targets (targets.json)
Operators Registered operator names; see the support matrix Operator catalog (operators.json)
heliaCORE floor The repository-wide minimum ns-cmsis-nn release; see the heliaCORE floor Version requirements (versions.json)

The operator catalog, its float16 and float32 dtypes included, and the target list at the 1.0.0 tag are the frozen support matrix for 1.x. Minor releases can add operators, dtypes and targets; only a major release removes one.

  • The atomiq110 target is experimental and outside that matrix: its name, memories and capabilities can change in any 1.x release until a board is available.
  • An operator’s dtypes and restrictions in the catalog describe what it accepts, and some are transcribed by hand. A minor or patch release can tighten an operator’s checks to reject a model its kernels cannot run correctly. That is a fix, not a breaking change: such a model never produced correct output.

For a promised class, the promise covers the members its documentation names: the attributes and methods its docstring describes, and the members the guides and examples use.

  • Any other public member of a promised class can change in a minor release, and a name with a leading underscore is private.
  • An enum’s promise covers its members’ UPPER_CASE names and their values; the values are the configuration spellings.

The ConversionResult views and the helia_aot.views records are promised like the rest of the manifest.

View field Meaning
operator type The canonical type: the name of its operator in the model file, a LiteRT builtin operator name or a custom operator’s canonical key. An operator a transform rewrote reports the type the transform generates; a depthwise convolution that DEPTHWISE_TO_CONV rewrites is CONV_2D. The vocabulary of type names is stable through 1.x; which operators a transform rewrites can change in any release.
operator source_indices Its operator in the model file. The provisional AirOperatorSource on the AIR operator records that operator’s name there.
tensor kind input for a model input, otherwise output for a model output, otherwise its storage: constant, persistent or scratch.
tensor input_index, output_index Its positions in the module’s input and output tables.

A 1.x release can add a field at the end of a view, or define macs and parameters for an operator type that reports None today; neither is a breaking change. AirOperatorSource, the record the LiteRT loader puts on each AIR operator, is provisional.

The configuration reference marks each setting’s stability, and config-schema.json records it per setting. A setting marked experimental is outside the promise; a reserved one is not implemented yet.

  • The run settings verbose, force, keep_work_dir and log_file are part of the configuration schema, like every other setting: they are YAML keys as well as flags, and they are promised the same way.
  • result_views is promised the same way, but it is a configuration key only. It changes what AotConverter.convert() returns, and the command line returns nothing, so it has no flag.
  • A configuration file has no version key. A file written for an earlier 1.x release keeps working on a later one. A file written for a later release can use a key that an earlier release rejects as unknown, with an error that names it.
  • The option keys of transforms[].options and memory.planner_options are described in the configuration guide and in Memory planners rather than exported as a schema. Exporting their schemas later adds a record and changes no key.

These are the JSON documents heliaAOT writes for scripts. The last column is everything a release promises about each one.

Output Written schema_version What is promised
<prefix>_plan.json By every conversion 1 The schema_version rule below; helia_aot.optimization.OptimizationPlan reads it by that rule
<prefix>_report.json By every conversion 1 The schema_version rule below for its fields; OptimizationReport reads it by that rule. Its figures, measurements and hints can change in any release
<prefix>_residency.json When memory.dump_residency_json is set 6 Only that it is written, with a schema_version. Its fields and values can change in any release, so check schema_version before reading it
platforms list --json, platforms show --json On request 1 Nothing: their fields and values can change in any release
plan-schema.json, report-schema.json With each release’s documentation data None Exactly what that release writes in the plan and the report, as JSON schemas

The offline model report’s download links save the same plan, report and residency files.

The plan and the report follow one rule:

  • Within a schema_version, a release can add an optional field, a knob, a knob value, or a member to the values a field takes. Renaming or removing a field, or changing what one means, increments schema_version, and only a major release does that.
  • A reader therefore ignores a field it does not know and keeps a knob, value or member it does not know. OptimizationPlan and OptimizationReport read that way: they read a file from any release with the same schema_version, older or newer, and reject another schema_version with an error that names both. The plan’s schedule section is the exception for a conversion that reads the plan as input (optimization.plan): heliaAOT applies it, so it rejects a field it does not know there, naming it. A release adds derived facts outside schedule, and an applied field outside it only with a new schema_version.
  • plan-schema.json and report-schema.json hold, under their json_schema key, a schema that lists every field, knob, value and member of the release that exported them and allows no other field (additionalProperties: false), except in a report hint’s facts, which is a free-form object.
  • Validate against that json_schema object, not the whole file.
  • A file validates against the schema of the release that wrote it, which the plan names in generator.helia_aot; a newer file need not validate against an older schema.

Three values in the plan are facts about the release that wrote it, not promises:

Value Fact
kernel.provider Names the planning rules behind a kernel choice. An opaque string: compare it, but do not parse it.
kernel.candidates The entries that release’s rules matched to the layer. A later release can add an entry or change a rule.
platform.capabilities What that release knew of the target. A later release can remove a capability from a target as well as add one.

The exit codes and their meanings are part of the promise. They are listed on the command line reference, which renders them from the command line’s own definition in cli.json and says which failures fall under each code. A typed error ends a command with the exit_code its class declares, which the Errors reference lists per class.

  • The command line exits 2 when your input is rejected: the command line, the configuration, a file it names (the model, the golden data, the output location), the choice of model type or format, or the target. That holds whether the check runs before conversion or after the model has loaded.
  • Among the rejections that exit 2: a missing or unreadable model (ModelLoadError), an existing output without --force (OutputExistsError), a missing golden archive (GoldenDataNotFoundError), out-of-range or duplicate test.state_feedback pairs, an out-of-range model.subgraph, and a float16 model on a target without FP16 support.
  • It exits 1 when a valid request fails while converting, such as a model construct heliaAOT cannot lower or memory that does not fit, and 130 on an interrupt.

module-layout.json marks each declaration in a module’s includes-api/ headers, and each struct field and enum member, with one of three stabilities. The Generated module page shows them.

Stability What it covers Promise
public What an application uses to run a model: <prefix>_model_init and <prefix>_model_run, the context’s callback, user_data, inputs and outputs, the status codes, the input and output tables and macros, the <PREFIX>_PRINTF, <PREFIX>_PUT_IN_* and <PREFIX>_PUT_CODE_IN_ITCM hooks, the test-case entry points and the API version. Names built from the model, such as <prefix>_input_0_size, follow its inputs and outputs. Removed, renamed or changed incompatibly only in a major release of heliaAOT; a minor release can add one.
advanced Context initialization (<prefix>_context_init, which <prefix>_model_init already calls; calling it after model_init clears the lifecycle latch), arena binding, constant hydration and the arena tables, for an application that manages a module’s memory itself. In a module with a stream pool, the pool region <prefix>_arena_pool_<memory> with its _size and _alignment, <prefix>_bind_arena in both arena modes (<prefix>_bind_arenas with caller-bound arenas only) and <prefix>_num_transfer_units. Such a module declares no <prefix>_arena_buffers table in either arena mode: its regions are reached through the bind table, which <prefix>_bind_arena writes. Which arenas a module has, and so the region names and sizes, follow the memory plan. Documented and versioned, not promised: a minor release can change one, and then the API version’s major part changes and the release notes say so.
internal Everything else: the per-operator _init and _run functions, the kernel descriptors in <prefix>_kernels.h, the tensor enumerators the importer names and numbers, the tensor descriptor table, and the context’s _lifecycle_state, tensor_ptrs and _arena_bases. Custom-operator code reaches tensors through some of them, under the experimental plugin contract described below. Can change in any release.

The operator callback’s op argument is the operator’s layer index for the operator states: 0 for the first operator in execution order, counting up by one. It is the index of the operator in ConversionResult.operators, and with module.schedule: table the callback reports the operators in that order. For the transfer states, which exist only in modules with a stream pool, it is the unit id.

module-layout.json also marks each file’s name:

Files Stability
The names listed in What a release promises public
The constant sidecars a caller that binds its own arenas loads, <prefix>_arena_const_<memory>__blob.bin and __source.bin advanced
Every other name: each operator’s <prefix>_<operator>_<n>.c and .h, <prefix>_operators.h, <prefix>_common.h, <prefix>_kernels.*, <prefix>_activations.*, the other sources and the CMSIS-Pack description internal, can change in any release; include <prefix>_model.h and build with the generated manifest rather than naming them

In 1.x, including <prefix>_model.h is sufficient for the public model initialization and execution API, its context type, and its input and output accessors and size macros. It includes <prefix>_tensors.h and <prefix>_context.h, and applications may rely on their public declarations being available through <prefix>_model.h; this does not promote advanced or internal declarations in those headers to public.

  • <prefix>_context.h includes the internal <prefix>_common.h, which includes <prefix>_platform.h, standard C headers and ns-cmsis-nn headers. That internal include chain is not a 1.x promise: include standard or kernel headers directly when using their declarations, and <prefix>_platform.h directly when using its hooks independently of the model API. Float kernel includes remain conditional on the generated model.
  • The public placement hooks are <PREFIX>_PUT_IN_<MEMORY>, <PREFIX>_PUT_IN_<MEMORY>_INIT and <PREFIX>_PUT_CODE_IN_ITCM, where <MEMORY> is PSRAM, DRAM, MRAM, SRAM, DTCM or ITCM. Their names and override points are part of the 1.x promise.
  • Specific linker section names and the platform’s default macro expansions are not promised: the application’s linker script and platform integration own the placement. Define overrides before the generated platform header is included, consistently for every generated translation unit.

What the hooks expand to today, which is not promised across 1.x:

Module type Data hooks Code hook
nsx Nothing __attribute__((section(".itcm_text"))) with GCC, Clang or Arm compiler macros, otherwise nothing
zephyr ITCM data __itcm_section; DTCM data __dtcm_bss_section or __dtcm_data_section on Apollo510 and Apollo330, __itcm_section on Apollo3 and Apollo4; the MRAM hook adds const; the other data hooks are empty __itcm_section
cmake and the rest Nothing Nothing

Zephyr’s section tags, and any application overrides, choose the actual linker sections.

<prefix>_status_t divides its values into ranges:

Range Meaning
0 Success.
1 to 999 The generated module’s own codes. New codes take unused values there, and existing ones are never renumbered.
1000 to 1999, <prefix>_status_custom_first to <prefix>_status_custom_last Custom operators. Generated code never returns one, and model_init and model_run forward a custom operator’s code unchanged.
Negative A kernel’s failure: an arm_cmsis_nn_status from ns-cmsis-nn, a status from the Ethos-U driver, or -1 from the Ethos-U wrapper when it cannot reserve the driver.
  • model_init also forwards whatever an application’s override of the weak <prefix>_hydrate_constants returns.
  • Every entry point returns int32_t, so hold a status in an int32_t, not in a <prefix>_status_t. The enum only names the values. It has no negative enumerator, so its type is unsigned, and its size can follow its range: under -fshort-enums, the Arm EABI default, the custom range makes it two bytes.

Names and units, final for C API 1.x:

Name Meaning
<prefix>_input_<n>_size, <prefix>_output_<n>_size, <prefix>_inputs_len, <prefix>_outputs_len Element counts.
<prefix>_input_<n>_nbytes, <prefix>_output_<n>_nbytes, <prefix>_tensor_io_t.size Byte counts.
<prefix>_tensor_io_t.data An int8_t * for every element type; cast it to the element type to read or write elements.
<PREFIX>_API_VERSION_*, <PREFIX>_PLAN_HASH, the platform hooks Spelled <PREFIX>_.
Every other name, including <prefix>_num_inputs, the I/O size macros and the arena size and alignment macros Spelled <prefix>_.

<prefix>_model.h defines <PREFIX>_API_VERSION_MAJOR, <PREFIX>_API_VERSION_MINOR and <PREFIX>_API_VERSION_PATCH, integers an application can test with #if. They version the public and advanced declarations, separately from heliaAOT’s own version; the Generated module page prints the version this release emits.

Part Changes when
major A public or advanced declaration is removed or renamed, or its type, signature, value or documented behaviour changes, so that code written against it can stop compiling or working. From heliaAOT 1.0.0 a public declaration changes that way only in a major release of heliaAOT. Before 1.0, a change such as 0.32.0’s meaning of the callback’s op argument is recorded under Changes before 1.0 with a minor C API bump.
minor One is added: a function, macro, type, status code, enum member, or a field at the end of a struct.
patch One is fixed to work as documented without its declaration changing.

Internal declarations, the bytes of the generated C, and the names and values the model or the memory plan decide, such as sizes, region names and <PREFIX>_PLAN_HASH, do not move the API version, and neither do the values of the <PREFIX>_API_VERSION_* macros themselves.

#include "aot_model.h"
#if AOT_API_VERSION_MAJOR != 1
#error "written against version 1 of the heliaAOT generated C API"
#endif

These can change in any release, including a patch release:

  • The code a module is built from. Kernel choice per layer, scratch sizes, arena layout and offsets, and the bytes of the generated C. A new release can emit different C for the same model and configuration.
  • Internal C declarations, the ones module-layout.json marks internal; see the generated C API.
  • Numerical results. A different kernel, rounding mode or approximation can change the output values a model produces.
  • Performance. Latency, image size and memory use. The benchmarks are dated records, not promises.
  • Report contents. The figures and hints in <prefix>_report.json. The plan records the choices.
  • The floor of a given model. See the heliaCORE floor.
  • Text meant for people. Error messages and hints, help text, console and log output. Match on the error class and the exit code, not on the wording.
  • CMSIS-Pack output, which is for evaluation until its packs pass full packchk validation. See Firmware integration.
  • The atomiq110 target, which is experimental until a board is available; see the support matrix.
  • Experimental settings. The offline model report (documentation.html), the greedy_by_size memory planner, the cmsis_pack value of module.type, the stream pool (memory.stream_pool), the plan input (optimization.plan), and any other setting or value the configuration reference marks experimental.
  • Python names outside the API manifest, including the lower-level helpers the custom operator starter uses, and any other import path for a name the manifest lists.
  • Provisional Python names. The manifest lists some names as provisional; see Provisional names.
    • helia_aot.air: everything but the core graph types and the operator-key helpers.
    • helia_aot.optimization: the knob and setting registries and the measurement records.
    • helia_aot.memory: the planner’s output types.
    • helia_aot.aot.operators: the custom-operator plugin surface (AotOperator, CtxBufUsage, OpCapability, register_default_aot_operators).
    • helia_aot.platforms: the platform model and its registration API (SocPlatform, get_platform, list_platforms, list_platform_names, register_platform, resolve_platform), while the registered platform names, platforms list, platforms show and the MemoryType and SocCapability names stay promised.
    • helia_aot.interpreters: AirInterpreter and create_interpreter.
    • helia_aot.registry: RegistryBundle.
  • The custom-operator plugin surface outside the API manifest. Custom-operator plugins are experimental in 1.x: the parser signature, the lower-level helpers and the C contract a custom operator’s code follows can change; AotOperator and its companions are provisional, and the other manifest names a plugin uses keep their promise. A stable plugin API is tracked in #829.
  • Kernel behavior on hosts other than Linux, and host builds of a generated module on Windows or macOS. See Supported hosts.
  • A major release can make a breaking change to a promised surface: remove or rename something, change a default, change what a value means, or raise the repository-wide heliaCORE floor.
  • A minor release adds to a surface: a command, flag, setting, value, operator, target, error class, optional file field or public C declaration.
  • A patch release fixes defects and changes nothing promised, except to make it work as documented.

Deprecated and renamed settings are marked in the configuration reference, and the release notes list each deprecation and each breaking change.

  • A deprecated setting or flag is still accepted, with a warning, for at least one minor release, and is removed only in a major release.
  • A renamed setting keeps its former key and flag, with a warning, until the next major release.
  • A removed setting or value is an error that names its replacement.

Deprecated in 1.x and removed in 2.0:

  • the list-targets and target-info commands, deprecated since 0.31.0. They print the same output as platforms list and platforms show NAME, and a warning on standard error.
  • the platform.speeds setting, deprecated since 0.32.0, which no conversion reads; it is accepted with a warning. An empty list, which configurations written by 0.31.0 and earlier hold, does not warn, and a configuration 0.32.0 or later writes leaves an empty one out.

A generated module calls heliaCORE, Ambiq’s neural-network kernel library, which is released as the ns-cmsis-nn package. Each module needs an ns-cmsis-nn release at or above its own floor. The module enforces it with a #error in <prefix>_common.h, records it as generator.cmsis_nn_required in <prefix>_plan.json and in its README, and a CMSIS-Pack names it as its dependency. Upstream Arm CMSIS-NN is not supported.

The repository-wide floor, listed on Version requirements, is the lowest any module needs, and it changes only in a major release.

  • A module’s own floor can be higher, because the kernels chosen for its layers can need a newer release. Kernel choice is not promised, so the floor a given model needs can rise in a minor release.
  • Read it from the module, not from the operator catalog, whose floor column covers only the float path.

heliaAOT runs on Python 3.11 to 3.14, on Linux, macOS and Windows, and the package metadata says Operating System :: OS Independent.

  • The promise on every host is the tool and the handoff: helia-aot converts a model, and the generated module builds for its target with the pinned Arm GNU Toolchain, in the cases continuous integration covers.
  • Kernel behavior is verified on Linux only: the tests that build and run a generated module against heliaCORE on the host, and the runs on the fixed virtual platform, are Linux jobs. Building a generated module for the host itself on Windows or macOS is not covered. Host coverage of the kernels themselves belongs to heliaCORE.

Continuous integration backs that promise this way:

  • Linux runs the test suite on each of those Python versions; TensorFlow does not install on 3.14, so the tests that need it skip there. It also installs the built wheel on Python 3.11 with every direct dependency at the lowest version pyproject.toml allows, and converts an example with it.
  • Windows, on every pull request marked ready, runs the unit suite with Python 3.11 without a heliaCORE checkout, so the tests that build against heliaCORE skip there, and cross-compiles the strict-compile cases with the Windows release of the pinned Arm GNU Toolchain against the released heliaCORE headers: the path from a conversion on Windows to a firmware build.
  • macOS runs the same cross-compile for each release and nightly on main, not on pull requests.
  • Each release installs the wheel and runs helia-aot --help on macOS and Windows, and builds a standalone binary on each of the three, which runs version, --help and one conversion with a generated test case on its own operating system before it is published.

A redirected stream on Windows uses the ANSI code page, which lacks glyphs that the results output draws with; some code pages, such as Japanese cp932, also lack glyphs in the help. Such a glyph prints as ? on standard output, and as Python’s escape, such as \u2713, on standard error, which carries progress, logs and errors.

The PyPI package is the supported install. The standalone Linux, macOS and Windows binaries are convenience builds of the same release, smoke-tested by build-binaries.yml and verified on publish; they are outside the 1.x promise.

The modules heliaAOT generates are licensed for Ambiq CPUs only; see Support, licence and contributing. Which compilers and build systems have been used to build them is on Toolchains and build environments.

The 0.x releases that changed a configuration, a program or a generated module are listed on Changes before 1.0.