Metadata-Version: 2.4
Name: darml
Version: 0.1.0
Summary: Model-to-firmware compiler for edge AI — Core (free, MIT)
Author: Darml Contributors
License: MIT
Project-URL: Homepage, https://darml.dev
Project-URL: Repository, https://github.com/darml-project/darml
Project-URL: Issues, https://github.com/darml-project/darml/issues
Project-URL: Documentation, https://github.com/darml-project/darml/blob/main/USAGE.md
Keywords: edge-ai,tinyml,firmware,tflite,onnx,esp32,stm32
Classifier: Development Status :: 3 - Alpha
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: System :: Hardware :: Hardware Drivers
Classifier: Operating System :: OS Independent
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: click>=8.1.0
Requires-Dist: httpx>=0.27.0
Provides-Extra: tflite
Requires-Dist: tflite-runtime>=2.14.0; extra == "tflite"
Requires-Dist: numpy>=1.26.0; extra == "tflite"
Provides-Extra: onnx
Requires-Dist: onnx>=1.16.0; extra == "onnx"
Provides-Extra: sklearn
Requires-Dist: joblib>=1.4.0; extra == "sklearn"
Requires-Dist: scikit-learn>=1.4.0; extra == "sklearn"
Requires-Dist: emlearn>=0.20.0; extra == "sklearn"
Requires-Dist: setuptools>=68.0; extra == "sklearn"
Provides-Extra: build
Requires-Dist: platformio>=6.1.0; extra == "build"
Provides-Extra: all
Requires-Dist: tflite-runtime>=2.14.0; extra == "all"
Requires-Dist: numpy>=1.26.0; extra == "all"
Requires-Dist: onnx>=1.16.0; extra == "all"
Requires-Dist: joblib>=1.4.0; extra == "all"
Requires-Dist: scikit-learn>=1.4.0; extra == "all"
Requires-Dist: emlearn>=0.20.0; extra == "all"
Requires-Dist: setuptools>=68.0; extra == "all"
Requires-Dist: platformio>=6.1.0; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
Requires-Dist: ruff>=0.6.0; extra == "dev"
Dynamic: license-file

# 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)

```bash
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](https://darml.dev/pricing) — 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).

```bash
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.

```bash
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.

```bash
# 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

```bash
# 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

```bash
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

```bash
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:

```bash
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](darml/container.py). No use
case, route, or CLI command changes required.

See [USAGE.md](USAGE.md) for end-to-end recipes and
[CLAUDE(1).md](CLAUDE(1).md) for the original spec.

## Testing

```bash
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](LICENSE). Use it for anything,
commercial or not, no restrictions.

`darml-pro` is **proprietary** — see [darml_pro/LICENSE](darml_pro/LICENSE).
A 14-day free trial starts on first install; commercial use after that
requires a license from https://darml.dev/pricing.
