# HEART Templates

**Starter code that gives any product a working HEART in minutes**

Release **v1.2611.3** (November 2026) · 17 templates (14 tested) · 20 more planned · Licence: **Apache-2.0**

---

## In one minute

A **template** is a small, complete program you copy into your product. It already does everything HEART Basic asks for. You change four lines (your product's name and ID) and write one function: *"is my product doing its main job?"* That's it: your product now has a HEART.

You can always build a HEART from scratch using the standard. Templates just save you the work, and they are tested against the standard on every release.

Every template says exactly which template and which release it is, for example:

```
heart/embeddedstandard/rust/v1.2611
heart/embeddedstandard/wasm-wat/v1.2611
```

---

## Licence

All templates are licensed under the **Apache License 2.0** (see `LICENSE` and `NOTICE`). You may copy them into any product, open or closed source, change them freely, and sell the result. Keep the licence and notice with any copy of the template files you hand on. Every file carries the line `SPDX-License-Identifier: Apache-2.0`, so the licence stays clear even when one file is copied on its own. The licence also grants a patent licence from contributors, which matters to companies building hardware.

## 1. Template names and versions

```
heart/embeddedstandard/ rust / v1.2611
                        ───┬── ──┬─────
                     template    version
                                 v1   = HEART standard version 1
                                 2611 = released in 2026, month 11
```

- **The template name** says the language or platform: `rust`, `c-baremetal`, `asm-arm-cortex-m`.
- **The version** is `v` + the HEART major version + `.` + the year and month of release (`YYMM`). So `v1.2611` is "HEART 1, November 2026". You can tell how old a template is just by reading its name.
- A newer number is always a newer release: `v1.2702` (February 2027) replaces `v1.2611`.

### Where the ID appears

You can always tell which template a system was built from:

| Where | Example |
|---|---|
| **In every file**, at the top | `Template: heart/embeddedstandard/go/v1.2611` |
| **In the code**, as a constant | `const template = "heart/embeddedstandard/go/v1.2611"` |
| **In the system's public Card**, in the `template` field | `"template": "heart/embeddedstandard/go/v1.2611"` |

The Card field is public, so a tester, a Gateway or the HEART-Rating client can see it without logging in. When you change the template, **keep the `template` value as it is**. It records where your code started, not who changed it.

### How often templates are updated

| When | What |
|---|---|
| **Every three months** (February, May, August, November) | A new release of all templates, such as `v1.2702`. It brings fixes, the latest rules of the standard, and new templates. |
| **When a security problem is found** | An urgent release of the affected templates, named after the month it comes out. |
| **Always** | Old releases stay downloadable, so a product built on `v1.2611` can always be compared with what it started from. |

A release is published only if **every testable template passes** the test harness (Section 6).

---

## 2. What every template does

Every template, in every language, does the same things. This is HEART Basic at Autonomy Level A1 (Parts 2 and 3 of the standard).

1. **Says who it is.** It publishes the HEART Card, including its template ID.
2. **Says how it is.** It publishes the Pulse: `healthy`, `failing` or `unknown`, with a counter.
3. **Checks its main job** every 30 seconds, using the one function you write. It needs no internet and no AI model.
4. **Raises an alert** with fault code `system.main-function-lost` when the job stops, and resolves it when the job comes back.
5. **Tells a person** through an `escalate` function you connect to your own route: app, email or dashboard.
6. **Answers in the standard way**: the `Heart-Version` header, CloudEvents envelopes, standard error messages, `404` for unknown paths and `501` for parts of HEART it does not offer.
7. **Uses the standard port** 43278, and falls back to 7685.

Every template comes with a demo: it pretends the main job has stopped while a file named `fault.flag` exists. Create the file to see the alert, and delete it to see it resolved.

**What templates do not do:** approvals, privacy filtering above `public`, logins, or acting on their own. Those are HEART Connected and Full. For those, build on the reference implementation (`heart-core-rs`) instead.

---

## 3. Two families

### Server templates: for anything that runs an operating system

They serve HEART themselves, over HTTP. Use them in apps, services, gateways, industrial PCs and embedded Linux boards.

### Device templates: for microcontrollers

A microcontroller is too small to serve web requests. Instead it sends one short line per event on its serial port, in the **HEART Line v1** format. The **bridge** (`templates/bridge/heart_bridge.py`), on a PC, Raspberry Pi or building controller, turns the lines into a full HEART. It can also push them to a HEART Gateway. This is the standard's *delegation* pattern (HEART Core Standard, Section 8).

```
 microcontroller ──serial──► bridge ──HTTP──► anyone asking "how are you?"
  (template)       lines      (PC, Pi)  └──► HEART Gateway (optional)
```

**HEART Line v1**: one JSON object per line, at most 1 KB, ending in a newline.

| Line | When | Example |
|---|---|---|
| `card` | Once, at start | `{"t":"card","id":"org.example.my-device","name":"My Device","version":"0.1.0","instance":"unit-1","template":"heart/embeddedstandard/c-baremetal/v1.2611","interval":30}` |
| `pulse` | Every interval | `{"t":"pulse","seq":12,"status":"healthy"}` |
| `alert` | When the main job stops | `{"t":"alert","code":"system.main-function-lost","severity":"critical"}` |
| `resolved` | When it comes back | `{"t":"resolved","code":"system.main-function-lost"}` |

The device notices problems itself, so it keeps working with no network. The bridge adds what a small device cannot: the time, unique IDs, and serving HTTP. If the device goes quiet for three intervals, the bridge reports it as `unknown` (the Flatline rule).

---

## 4. The templates in this release

**Tested** means built and run on Linux by `tools/test_templates.py`: every reply checked against the official schemas, then rated by the HEART-Rating client. All tested templates score **8.9, Good (provisional)**. The rating is provisional only because the hands-on tests (Part 9) must be done by you, on your product.

### Server templates

| Template ID | Language | For | Status |
|---|---|---|---|
| `heart/embeddedstandard/python/v1.2611` | Python 3.8+ | Linux, Raspberry Pi, scripts, services | Tested · 8.9 |
| `heart/embeddedstandard/javascript-node/v1.2611` | JavaScript (Node 18+) | Services, Electron apps | Tested · 8.9 |
| `heart/embeddedstandard/go/v1.2611` | Go 1.20+ | Embedded Linux (ARM, RISC-V, MIPS), services | Tested · 8.9 |
| `heart/embeddedstandard/rust/v1.2611` | Rust (std only, no crates) | Embedded Linux, services | Tested · 8.9 |
| `heart/embeddedstandard/c-posix/v1.2611` | C99, no heap, one thread | Embedded Linux, Yocto, Buildroot, OpenWrt | Tested · 8.9 |
| `heart/embeddedstandard/java/v1.2611` | Java 11+ (JDK only) | Industrial PCs, gateways | Tested · 8.9 |
| `heart/embeddedstandard/php/v1.2611` | PHP 8 | Web back ends, CMS plug-ins | Tested · 8.9 |
| `heart/embeddedstandard/ruby/v1.2611` | Ruby 3 | Web back ends | Tested · 8.9 |

### Device templates

| Template ID | Language | For | Status |
|---|---|---|---|
| `heart/embeddedstandard/c-baremetal/v1.2611` | C99, no heap, no stdio | Any microcontroller | Tested on Linux · 8.9. The Cortex-M port compiles but has not run on a chip. |
| `heart/embeddedstandard/micropython/v1.2611` | MicroPython | ESP32, Raspberry Pi Pico, STM32 | Tested under CPython · 8.9. Not yet on a board. |
| `heart/embeddedstandard/wasm-wat/v1.2611` | WebAssembly text, hand-written | Browsers, plug-in hosts, WAMR and wasm3 on microcontrollers | Tested in Node · 8.9 |
| `heart/embeddedstandard/asm-x86-64-linux/v1.2611` | x86-64 assembly | x86-64 Linux, and as the model for other assembly ports | Tested · 8.9 |
| `heart/embeddedstandard/asm-arm-cortex-m/v1.2611` | ARM Thumb-2 assembly | Cortex-M3/M4/M7/M33 | **Untested**: no ARM assembler was available |
| `heart/embeddedstandard/asm-riscv32/v1.2611` | RISC-V assembly (RV32IM) | ESP32-C3/C6, GD32V, SiFive, CH32V | **Untested**: no RISC-V assembler was available |
| `heart/embeddedstandard/arduino/v1.2611` | Arduino C++ | Uno, Nano, Mega, ESP32, RP2040 | **Untested**: arduino-cli was not available |
| `heart/embeddedstandard/bridge/v1.2611` | Python 3.8+ | The PC or controller next to the devices | Tested with every device template |

### Watching devices from anywhere: HEART Hub

The `python` and `esp32-full` templates can report their health to **`https://heartcortex.ai`**, or to your own site running the same open code (`heart-monitor/`). It is **off by default**: set `MONITOR = True` (Python) or `HEART_MONITOR` in menuconfig (ESP32). At first start the device shows a device ID and claim code; its owner registers it, then sees its health at `heartcortex.ai/device/<ID>`. Only public health data is ever sent. See `spec/HEART-Monitor-1.0.md`.

**Asking the owner (also off by default).** A device can ask its owner to approve a change on the site, from anywhere: `ask_owner(title, change, apply)` in Python, or `HEART_MONITOR_APPROVALS` in menuconfig for the ESP32, where it works alongside the device's button. The owner approves with a code emailed to them; the site sees only a title and the change. The device acts only on a decision signed by the site's Ed25519 key, which it pinned at its first hello, and at most 300 seconds old (presence method `remote-site`, API Standard 6.3). Physical changes are offered only with a second setting: `HEART_MONITOR_APPROVALS_PHYSICAL` (Python) or `HEART_MONITOR_APPROVALS_PHYSICAL` in menuconfig.

### An AI brain on a lease (brain module, new in v1.2611.3)

The `python` and `esp32-full` templates can let an AI model explain their alerts, under a **brain lease** from a **Command Center** (API Standard 7.4; `spec/HEART-Command-Center-1.0.md`). It is **off by default**: set `BRAIN = True` (or `HEART_BRAIN=1`) in Python, or `HEART_BRAIN` in menuconfig for the ESP32. It needs the monitor on, because the monitor site is also the Command Center, and the site key the device pinned at its first hello signs everything.

- **No model keys on the device.** The Command Center holds them. The device renews its lease when a third of it is left, and asks for an explanation only while it holds a lease it checked: signed with the pinned key, for this system, at most 300 seconds long, counted on the device's own clock.
- **Every answer is checked before it is shown**: signed for a request this device sent, under its current lease, by a model the lease names. It is shown to the owner as "Suggested by an AI model: ..." and never acted on. A forged answer is rejected, counted in `rejectedAnswers`, and raises `ai.answer-rejected`. Three in an hour, and the device cuts its own brain.
- **Brainless is safe.** When the lease runs out (even if the link is blocked) or a signed `brain-off` arrives, the device is brainless at once: it keeps noticing and alerting, with no AI. `GET /heart/v1/brain` says so to anyone, with the reason, and the owner's Pulse shows `autonomy.limitedBy: brain-cut`.
- **Restoring needs the owner.** After a cut, the brain comes back only once the owner approves `POST /heart/v1/brain/restore`: with the button on the ESP32; in Python, on the monitor site (`MONITOR_APPROVALS`), with a proof sent in the request (`actionId` and `presence`, method `remote-site`), or by creating `brain-restore.flag` at the machine. If approvals are off for the device on its Hub page, Python refuses the request at once with `403 presence-required` and says how to go on, so it never waits unseen. A lease that simply ran out is not a cut.
- **No auto mode.** Neither template runs a local model, so neither has auto mode. In Python, `PUT /heart/v1/brain/offline` with `{"enabled": false}` answers the brain view, and `{"enabled": true}` answers `409 conflict`.

Tested by `tools/test_brain.py` (Python, and both templates against the real Command Center in `heart-monitor/`) and `tools/test_full_starter.py` (the ESP32 core).

### Restart and sleep (lifecycle, new in v1.2611.3)

Three templates can carry out the `lifecycle` module (API Standard 13.2 rule 3), so a person can restart a product, or put it to sleep, through HEART. It is **off by default** in Python and Node, and needs the owner key in all three.

| Template | Operations | How it is carried out | What waits for a person |
|---|---|---|---|
| `python` | `restart`, `shutdown` | `before_lifecycle()` finishes the product's work, then `carry_out()` starts the program again in place, or ends it | A force restart, and a shutdown (only a person can start it again): run at once with a `remote-site` proof sent in the request (`actionId` and `presence`); otherwise approved by the owner on the monitor site with `MONITOR_APPROVALS`. Refused at once with `403 presence-required` when the owner cannot be asked there: `MONITOR_APPROVALS` is off, or approvals are off for the device on its Hub page |
| `javascript-node` | `restart`, `shutdown` | `beforeLifecycle()`, then `carryOut()` starts a new process and ends the old one | A force restart and a shutdown: always refused with `403 presence-required`, and a request that sends `presence` with `403 presence-invalid`, as this starter can check no proof. Do them at the device |
| `esp32-full` | `restart`, `sleep` (deep, woken by the timer or the button) | `heart_port_lifecycle_ready()`, then `esp_restart()` or `esp_deep_sleep_start()` | A force restart: a press of the device's button |

In all three: turn it on with `LIFECYCLE` (or `HEART_LIFECYCLE=1`) in Python and Node; it is always on in the ESP32 starter.

- **A graceful restart that cannot finish in time fails, and is never forced.** The product's hook says when it is ready. If it is not ready by `timeoutSec` (default 60), the Action ends `failed` and nothing restarts.
- **Every answer is an Action** with `nextReachableAt`: when the system expects to answer again. A shutdown says `null`, with a note.
- **The Action survives the restart or sleep.** Ask for `/heart/v1/actions/{id}` afterwards and it says `succeeded`. Python and Node keep it in `heart-lifecycle.json`, and the ESP32 in RTC memory, which also keeps a Stop through a restart.
- **The client may name the Action** with `actionId` (a UUID), so it knows the digest before it sends the request (API Standard 6.3). A reused `actionId` gets `409`.
- **Every lifecycle `POST` (and Python's `brain/restore`) needs an `Idempotency-Key` header**, 8 to 255 characters (API Standard 5.5). A retry with the same key and body gets the first answer and runs nothing; another body gets `422 idempotency-conflict`. Keys are kept for 24 hours, across restarts.
- **The Action operations come with it** (API Standard 2): `GET /heart/v1/actions` (newest first, `limit` up to 500, `cursor`), `GET /heart/v1/actions/{id}` and `POST /heart/v1/actions/{id}/decision`. `deny` and `cancel` work on a waiting Action. `approve` is refused with `403 capability-not-allowed`, because the owner key is the only caller and the one who asked never approves their own request. The owner approves on the monitor site, or sends a proof with the request.
- **Refusals:** an unknown operation gets `404`, one not offered `501`, unknown fields or `delaySec` above 0 `400` (there is no schedules module), and a second operation while one is under way `409`.

Try it: create a file named `busy.flag` and ask for a restart with `{"timeoutSec": 2}`. It fails, and the program keeps running.

### Full starter templates

These do more than HEART Basic: a small HTTPS server (F1), every signal from a signal table (F2), analysis by a cloud AI model through a Reasoning Gateway (F3), and commands from people, with the device's own button as proof of presence for anything physical (F4).

| Template ID | Language | For | Status |
|---|---|---|---|
| `heart/embeddedstandard/esp32-full/v1.2611` | C99 core + ESP-IDF 5.2 port | ESP32, ESP32-S3, ESP32-C3, ESP32-C6 | Core tested on Linux · 8.9, plus 30 tests of F2–F4, lifecycle and the brain lease (also under AddressSanitizer). **The ESP-IDF port has not yet been compiled or run on a chip.** |

---

## 5. The full list: planned templates

These came out of the brainstorm, grouped by where they run. They will be added in later releases, most useful first.

| Template | Language | For | Why it matters |
|---|---|---|---|
| `rust-heart-core` | Rust + the `heart-core` crate | Embedded Linux | **HEART Full** from the reference implementation: approvals, Valve, custom commands |
| `browser-worker` | JavaScript + heart-core WASM | Web apps | Full HEART in a browser tab |
| `docker-sidecar` | Container running `heartd` | Kubernetes, Docker | Add HEART to any service without touching its code |
| `cpp-posix` | C++17 | Embedded Linux, Qt devices | Many product teams work in C++ |
| `csharp-dotnet` | C# (.NET 8) | Windows, industrial PCs | |
| `kotlin-android` | Kotlin | Android apps and devices | |
| `swift` | Swift | iOS, macOS | |
| `dart-flutter` | Dart | Flutter apps | |
| `typescript-deno` | TypeScript | Deno, Bun, edge | |
| `elixir` | Elixir / Erlang | Nerves devices, telecom | |
| `lua-openwrt` | Lua | OpenWrt routers, NodeMCU | |
| `rust-embedded-nostd` | Rust `no_std` | Cortex-M, RISC-V, ESP32 | |
| `zephyr` | C (Zephyr module) | Zephyr boards | |
| `freertos` | C (FreeRTOS task) | FreeRTOS microcontrollers | |
| `zig` | Zig | Embedded and systems | |
| `ada-spark` | Ada / SPARK | Rail, avionics, defence | Outside the safety function only |
| `iec61131-st` | IEC 61131-3 Structured Text | PLCs (CODESYS, TwinCAT, Siemens) | Factory controllers, on the supervisory side only |
| `asm-avr` | AVR assembly | ATmega, ATtiny | The smallest 8-bit chips |
| `asm-xtensa` | Xtensa assembly | ESP32 (original), ESP8266 | |
| `mqtt-device` | C + MQTT 5 | Devices already using MQTT | Must follow the signed-command rules of Advisory C5 |

---

## 6. How templates stay robust

Every release must pass these checks before it is published:

1. **Build** every template with warnings treated as errors, where the language allows.
2. **Run** it with a simulated fault.
3. **Check every reply** against the official HEART schemas: Card, Pulse, alerts, errors and envelopes.
4. **Check the behaviour**: the fault is noticed, the alert has the right fault code, unknown paths give `404`, and parts not offered give `501`.
5. **Rate it** with the HEART-Rating client and the latest metrics. A template may not fail any test.
6. **Check the ID**: every file states its template ID, and the Card's `template` field matches it.

```sh
pip install 'jsonschema[format]'
python3 tools/test_templates.py            # all templates this machine can run
python3 tools/test_templates.py rust go    # just these
python3 tools/build_catalog.py             # writes catalog.json with the results
```

Templates that cannot be tested on the release machine are clearly marked **Untested**, with the reason. They are never called tested.

### Rules for template authors

- One file where possible. No dependencies beyond the language's standard library.
- Mark everything the user must change with `CHANGE`.
- The demo fault is always `fault.flag`, so every template can be tested the same way.
- Plain HTTP only on `127.0.0.1`. On a network, use TLS or a HEART Gateway (API Standard 8.2).
- Never put HEART in a safety function or a control loop (API Standard 15). Templates only watch and report.

---

## 6a. Tools that come with the templates

| Tool | What it does |
|---|---|
| `tools/heart_signals.py` | Drafts a **signal table** (`signals.json`) from a Modbus register map, a CAN database or a firmware header, then checks, seals and exports it: as `heartd` property definitions, or as a C table (`--out heart_signals.h`) for the Full starters. See `spec/HEART-Signal-Tables-1.0.md`. |
| `tools/heart_mdns.py` | **Finds** HEART systems on a local network (`_heart._tcp`), or **announces** one from its public Card. See Part 4, Section 3.4. |
| `tools/avahi/heart.service` | Announces a Linux device through Avahi. Copy it to `/etc/avahi/services/`. |
| `tools/test_templates.py`, `tools/build_catalog.py` | Test every template, and build the catalog |
| `tools/test_full_starter.py` | Tests the Full starter functions F2–F4 of `esp32-full` on Linux, and its brain lease (`--asan` for memory checks) |
| `tools/test_brain.py`, `tools/fake_cc.py` | Tests the brain lease and signed answers in `python`, and in both templates against the Command Center of `heart-monitor/` (`--no-site` to skip that part) |

## 7. Choosing a template

| Your product | Use |
|---|---|
| An app or service on Linux, macOS or Windows | The server template for your language |
| An embedded Linux board (Raspberry Pi, i.MX, Yocto) | `c-posix`, `go` or `rust` |
| An ESP32 on Wi-Fi that should serve its own signals, explain its alerts and take commands | `esp32-full` |
| A microcontroller with a serial port | `c-baremetal`, or `micropython`, `arduino`, or an assembly port, plus the bridge |
| A web page or a plug-in host | `wasm-wat` |
| A product that must approve actions, filter private data or run custom commands | Not a template: use `heart-core-rs` (HEART Full) |

---

## 8. Downloading

The HEART-Rating service also serves the templates (see `heart-rating/README.md`):

| Endpoint | Gives |
|---|---|
| `GET /v1/templates` | The catalog: every template, its ID, version and test result |
| `GET /v1/templates/{name}` | One template's details |
| `GET /v1/templates/{name}/{version}.zip` | The template as a zip, with the bridge included for device templates |

For example: `curl -O https://<service>/v1/templates/rust/v1.2611.zip`
