Skip to main content

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

darml-0.1.0.tar.gz (87.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

darml-0.1.0-py3-none-any.whl (109.6 kB view details)

Uploaded Python 3

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

Hashes for darml-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f7e2de386dcdec861f5e701b7f754031b2ae50df97ee3d35b25bbe1d18c219ff
MD5 50d00df61532ff2527cdbd1cfe3688ff
BLAKE2b-256 616caaf04b731cd2e594789ec2acbd9f2c2388d539d7576378cf0aca7bd563a1

See more details on using hashes here.

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

Hashes for darml-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ec8f2b26824e564ef47d30935f59e5ee6e888c4adea5e506779e459a1ee94484
MD5 1610fa56a7ce02699b8bf31fc5689d0f
BLAKE2b-256 4863cb80a2d86d89afcf51f0da6c089fd9bd447805e7d6ed52bdf8e121fdd97e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page