Model-to-firmware compiler for edge AI — Core (free, MIT)
Project description
Darml — Model in. Firmware out.
A model-to-firmware compiler for edge AI. Upload a trained model
(.tflite, .onnx, or sklearn .pkl), pick a target hardware, and get
a flashable firmware binary or a drop-in C library.
Ten supported targets across five hardware tiers — from a 2 KB AVR up to a multi-GB Jetson — with a single uniform pipeline:
parse → check size → quantize → convert → compile → package
Quick start (3 commands)
pip install darml # free, MIT
darml build path/to/model.tflite --target esp32-s3
darml flash darml-<build_id>.zip --port /dev/ttyUSB0
The first build downloads the cross-compiler toolchain (~5 minutes, ~500 MB per platform). Build cache and other speedups are part of Darml Pro — a 14-day free trial starts automatically when you install the Pro package.
Two packages, one tool
| Package | License | Distribution | What you get |
|---|---|---|---|
darml |
MIT | PyPI | Full pipeline, all 11 targets, CLI, serial output, 5 builds/day |
darml-pro |
Proprietary | Private index | INT8 auto-quantization, ONNX→TFLite, web dashboard, build cache, HTTP/MQTT output, unlimited builds, email support |
Pro is opt-in. Importing darml works on its own; if darml-pro is also
installed, it auto-registers into Core's plugin registry — no
configuration needed beyond a license key (or the 14-day trial).
pip install darml # free tier, 5 builds/day
pip install darml darml-pro # 14-day trial, then bring your license key
export DARML_LICENSE_KEY=darml_pro_… # after purchase
darml version # see what's active
Hardware support
| Target | RAM | Flash | Runtime | Firmware build | Library mode |
|---|---|---|---|---|---|
avr-mega328 |
2 KB | 32 KB | emlearn | yes | yes |
avr-mega2560 |
8 KB | 256 KB | emlearn | yes | yes |
stm32f4 |
320 KB | 1 MB | TFLite Micro | yes | yes |
stm32h7 |
1 MB | 2 MB | TFLite Micro | yes | yes |
stm32n6 |
1.5 MB | 4 MB | TFLite Micro | yes | yes |
esp32 |
520 KB | 4 MB | TFLite Micro | yes | yes |
esp32-s3 |
512 KB+8 MB | 16 MB | TFLite Micro | yes | yes |
rpi4 / rpi5 |
4–8 GB | — | TFLite | tarball | n/a |
jetson-nano |
4 GB | — | TensorRT/TFLite | tarball | n/a |
jetson-orin |
8 GB | — | TensorRT/TFLite | tarball | n/a |
darml targets prints this list at runtime.
CLI reference
All commands accept --help for detailed flags.
darml info <model_file>
# Print model format, shapes, op count, quantization status.
darml check <model_file> --target <target>
# Estimate RAM/Flash footprint, warn if it won't fit.
darml targets
# List supported hardware targets.
darml build <model_file> --target <target>
[--quantize]
[--output firmware|library|both]
[--report serial|http|mqtt]
[--local | --remote --server URL]
[--out PATH]
darml flash <firmware_file> --port <serial_port> --target <target>
# Shells out to esptool.py / STM32_Programmer_CLI / avrdude.
darml serve
# Start the HTTP server (defaults: 0.0.0.0:8080).
Local vs remote builds
darml build runs in-process by default — no server required. Pass
--remote --server http://your-darml-host:8080 (or set DARML_SERVER)
to dispatch the build to a running Darml instance and download the
artifact.
# Local (default): in-process, uses the toolchain installed in this venv
darml build model.tflite --target esp32-s3
# Remote: HTTP to a server (CI host, shared build farm, etc.)
darml build model.tflite --target esp32-s3 --remote --server http://darml.lan:8080
HTTP API reference
GET /health → {"status":"ok","version":"..."}
GET /v1/targets → list of supported targets
POST /v1/info (file=…) → model metadata (JSON)
POST /v1/check (file=…, target=…) → metadata + size verdict
POST /v1/build (file=…, target=…, → 202 Accepted, returns build_id
quantize?, output?,
report_mode?, report_url?)
GET /v1/build/{id} → status + warnings
GET /v1/build/{id}/download → artifact .zip
GET / → drag-and-drop dashboard
CORS is configurable via DARML_CORS_ORIGINS (comma-separated; default
*). All upload endpoints enforce DARML_MAX_MODEL_SIZE_MB and return
HTTP 413 if exceeded.
curl example
# Get model metadata
curl -F "file=@model.tflite" http://localhost:8080/v1/info
# Kick off a build, poll, download
BUILD_ID=$(curl -s -F "file=@model.tflite" -F "target=esp32-s3" \
-F "output=firmware" \
http://localhost:8080/v1/build | jq -r .build_id)
curl http://localhost:8080/v1/build/$BUILD_ID
curl -o darml.zip http://localhost:8080/v1/build/$BUILD_ID/download
Self-hosted setup
Docker
docker compose up --build
# → http://localhost:8080
The image pre-fetches PlatformIO platforms for ESP32 / STM32 / AVR so
first-time MCU builds inside the container start fast. Build artifacts
and the cache persist in named volumes (darml_data, darml_pio).
Bare metal
git clone https://github.com/darml-project/darml.git
cd darml
python3 -m venv .venv && . .venv/bin/activate
pip install -e '.[full]' # all model formats + PlatformIO
darml serve # → http://localhost:8080
Optional dependency groups
The base install only pulls fastapi, uvicorn, click, httpx. Pick
extras based on which paths you need:
pip install 'darml[onnx]' # ONNX parsing + dynamic INT8 quant
pip install 'darml[onnx-tflite]' # ONNX → TFLite (TF + onnx2tf chain)
pip install 'darml[sklearn]' # sklearn → AVR via emlearn
pip install 'darml[build]' # PlatformIO for MCU firmware builds
pip install 'darml[full]' # everything above
pip install 'darml[dev]' # pytest + ruff
Configuration
All knobs are environment variables — .env.example lists them all.
| Variable | Default | Purpose |
|---|---|---|
DARML_HOST |
0.0.0.0 |
server bind address |
DARML_PORT |
8080 |
server port |
DARML_DATA_DIR |
./data |
persisted build artifacts |
DARML_MAX_MODEL_SIZE_MB |
100 |
reject larger uploads |
DARML_BUILD_TIMEOUT |
300 |
hung-build kill threshold (seconds) |
DARML_PLATFORMIO_PATH |
pio |
override PlatformIO CLI path |
DARML_USE_SQLITE |
false |
persist build records to SQLite |
DARML_SQLITE_PATH |
./data/darml.db |
SQLite location |
DARML_CORS_ORIGINS |
* |
comma-separated CORS allow list |
DARML_CACHE_ENABLED |
true |
content-addressed build cache |
DARML_CACHE_DIR |
./data/cache |
cache location |
DARML_DEBUG |
false |
verbose logs + uvicorn reload |
Build cache (Pro feature)
When darml-pro is installed, every build is keyed by
sha256(model_bytes) + target + options. A repeat build with the same
inputs returns the cached artifact in O(copy) time — saves the entire
3–5 min MCU compile. The cache lives at DARML_CACHE_DIR; clear with
rm -rf or set DARML_CACHE_ENABLED=false to bypass.
Without Pro, every build runs fresh.
Free tier limits
darml Core (free) caps you at 5 builds per UTC-day, tracked locally at
~/.darml/counter. The CLI shows your remaining count after each build.
Pro is unlimited.
$ darml build model.tflite --target esp32-s3
Build completed: 5f3e…
Artifact: data/builds/5f3e…/5f3e….zip
4 builds remaining today (resets at midnight UTC). Need unlimited?
https://darml.dev/pricing
The counter is per-machine and per-user. Removing the file resets it. This is friction-as-marketing, not DRM — we don't ship hostile bypass prevention. The Pro upgrade sells convenience and unlimited usage, not counter circumvention.
Architecture
Clean architecture with a strict dependency rule:
domain ← application ← infrastructure ← interfaces
- Domain — entities, enums, target registry, exceptions. Zero deps.
- Application — use cases + abstract ports + the build pipeline.
- Infrastructure — concrete adapters (parsers, builders, cache, PlatformIO, ONNX runtime, etc.).
- Interfaces — FastAPI routes + Click CLI. Thin controllers.
Adding a new target = one Target entry, one FirmwareBuilderPort
implementation, one line in container.py. No use
case, route, or CLI command changes required.
See USAGE.md for end-to-end recipes and CLAUDE(1).md for the original spec.
Testing
pip install 'darml[dev]'
pytest # unit tests
python tests/fixtures/make_real_models.py # generate the 5 fixtures
python examples/realmodel_matrix.py # 5 × 10 parse + check matrix
python examples/esp32_demo.py # full ESP32 firmware build
python examples/stm32_demo.py # full STM32 firmware build
python examples/iris_avr_demo.py # sklearn → AVR library
python examples/onnx_rpi_demo.py # ONNX → quantized → RPi tarball
License
darml (Core) is MIT — see LICENSE. Use it for anything,
commercial or not, no restrictions.
darml-pro is proprietary — see darml_pro/LICENSE.
A 14-day free trial starts on first install; commercial use after that
requires a license from https://darml.dev/pricing.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file darml-0.1.0.tar.gz.
File metadata
- Download URL: darml-0.1.0.tar.gz
- Upload date:
- Size: 87.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f7e2de386dcdec861f5e701b7f754031b2ae50df97ee3d35b25bbe1d18c219ff
|
|
| MD5 |
50d00df61532ff2527cdbd1cfe3688ff
|
|
| BLAKE2b-256 |
616caaf04b731cd2e594789ec2acbd9f2c2388d539d7576378cf0aca7bd563a1
|
File details
Details for the file darml-0.1.0-py3-none-any.whl.
File metadata
- Download URL: darml-0.1.0-py3-none-any.whl
- Upload date:
- Size: 109.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ec8f2b26824e564ef47d30935f59e5ee6e888c4adea5e506779e459a1ee94484
|
|
| MD5 |
1610fa56a7ce02699b8bf31fc5689d0f
|
|
| BLAKE2b-256 |
4863cb80a2d86d89afcf51f0da6c089fd9bd447805e7d6ed52bdf8e121fdd97e
|