When you’d care
Most application developers consume Syni through a language SDK — the Flutter SDK, and (later) Swift / Kotlin equivalents — and never see the C ABI. This page is for the people who do:- SDK authors adding a new language binding over the same engine.
- Native integrators plugging the runtime into a non-Flutter / non-mobile surface (a CLI tool, a server worker, a desktop app).
- Debuggers chasing symbol-level issues across the FFI boundary.
ABI rules
- The C ABI is the stable boundary. Runtime internals are not.
- Symbols, struct shapes, error codes, and lifetimes documented here are the contract — they MUST NOT change without a major version bump on the runtime package.
- Every handle has a
_destroycounterpart. Leaks are the caller’s fault. - All strings are UTF-8, NUL-terminated, owned by the caller of the API unless explicitly documented otherwise.
Install
Runtime artifacts are distributed viadist.synheart.ai and installed by the
Synheart CLI:
1. Handle and lifecycle
The engine is opaque — callers hold a singleSyniRuntimeHandle* for the
lifetime of a load.
createvalidates config and allocates resources but does not mmap the model file.loadmmaps the model, materialises tokenizer + grammar, and is the expensive call (~hundreds of ms cold).destroyis safe to call at any state. Subsequent calls on the handle are undefined.
2. Configuration
- Apple: set
metal = truefor GPU acceleration. Falls back to CPU automatically if Metal is unavailable. - Android: CPU only — the
metalandcudaflags are ignored. - Backend:
CANDLEis the default — it’s what the published artifacts ondist.synheart.aiship with.LLAMArequires a runtime variant built with the llama.cpp backend enabled, which is not part of the default published artifacts today.
3. Generation
Generation is request/response, optionally streamed via a callback.0 to continue, non-zero to cancel. On
cancel, syni_generate returns SYNI_STATUS_CANCELLED and out_full
contains the partial response so far.
4. Grammar-constrained decoding
Whengrammar_gbnf is non-NULL, the runtime constrains decoding to outputs
valid against the GBNF. Bind grammars to schemas via the
Syni Spec registry:
SYNI_STATUS_INVALID_GRAMMAR at request
time, not at generation time.
5. Status codes
OK— success.INVALID_CONFIG/MODEL_NOT_FOUND— caller bug; surface verbatim.LOAD_FAILED— likely corrupted model file or unsupported architecture.INVALID_GRAMMAR— GBNF didn’t parse against the schema.OOM— model too large for device; suggest a smaller variant.CANCELLED— caller-initiated; not an error.INTERNAL— bug in the runtime; capture logs and file an issue.
6. Memory management
- Every
*_createhas a matching*_destroy. Caller owns the handle. - Returned C strings (
out_full) are heap-allocated by the runtime and must be freed withsyni_string_free. - The runtime is thread-safe per handle: concurrent calls on the same
SyniRuntimeHandleare serialised internally; concurrent calls on different handles run in parallel.
7. Backends
Only the Candle backend is published to
dist.synheart.ai today. The
llama.cpp backend exists in the runtime but is not part of the default
published variant; treat it as a future option rather than something
you can opt into from the released artifacts.
Symbols this page does not document
This page covers the stable surface only. The runtime exports a number of internal symbols (_dbg_*, _unstable_*) for diagnostics — these
may change without notice between patch releases.
Related
- Syni overview — how the runtime fits with the Flutter SDK and the spec
- Syni Flutter SDK — the Dart wrapper over this ABI
- Syni Spec — persona / grammar / safety contracts the runtime consumes
- C header:
synheart/vendor/syni-runtime/headers/syni_ffi.hafter install