HEART Embedded Systems logoHEART

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:

WhereExample
In every file, at the topTemplate: heart/embeddedstandard/go/v1.2611
In the code, as a constantconst 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#

WhenWhat
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 foundAn urgent release of the affected templates, named after the month it comes out.
AlwaysOld 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.

LineWhenExample
cardOnce, 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}
pulseEvery interval{"t":"pulse","seq":12,"status":"healthy"}
alertWhen the main job stops{"t":"alert","code":"system.main-function-lost","severity":"critical"}
resolvedWhen 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 IDLanguageForStatus
heart/embeddedstandard/python/v1.2611Python 3.8+Linux, Raspberry Pi, scripts, servicesTested · 8.9
heart/embeddedstandard/javascript-node/v1.2611JavaScript (Node 18+)Services, Electron appsTested · 8.9
heart/embeddedstandard/go/v1.2611Go 1.20+Embedded Linux (ARM, RISC-V, MIPS), servicesTested · 8.9
heart/embeddedstandard/rust/v1.2611Rust (std only, no crates)Embedded Linux, servicesTested · 8.9
heart/embeddedstandard/c-posix/v1.2611C99, no heap, one threadEmbedded Linux, Yocto, Buildroot, OpenWrtTested · 8.9
heart/embeddedstandard/java/v1.2611Java 11+ (JDK only)Industrial PCs, gatewaysTested · 8.9
heart/embeddedstandard/php/v1.2611PHP 8Web back ends, CMS plug-insTested · 8.9
heart/embeddedstandard/ruby/v1.2611Ruby 3Web back endsTested · 8.9

Device templates#

Template IDLanguageForStatus
heart/embeddedstandard/c-baremetal/v1.2611C99, no heap, no stdioAny microcontrollerTested on Linux · 8.9. The Cortex-M port compiles but has not run on a chip.
heart/embeddedstandard/micropython/v1.2611MicroPythonESP32, Raspberry Pi Pico, STM32Tested under CPython · 8.9. Not yet on a board.
heart/embeddedstandard/wasm-wat/v1.2611WebAssembly text, hand-writtenBrowsers, plug-in hosts, WAMR and wasm3 on microcontrollersTested in Node · 8.9
heart/embeddedstandard/asm-x86-64-linux/v1.2611x86-64 assemblyx86-64 Linux, and as the model for other assembly portsTested · 8.9
heart/embeddedstandard/asm-arm-cortex-m/v1.2611ARM Thumb-2 assemblyCortex-M3/M4/M7/M33Untested: no ARM assembler was available
heart/embeddedstandard/asm-riscv32/v1.2611RISC-V assembly (RV32IM)ESP32-C3/C6, GD32V, SiFive, CH32VUntested: no RISC-V assembler was available
heart/embeddedstandard/arduino/v1.2611Arduino C++Uno, Nano, Mega, ESP32, RP2040Untested: arduino-cli was not available
heart/embeddedstandard/bridge/v1.2611Python 3.8+The PC or controller next to the devicesTested 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.

TemplateOperationsHow it is carried outWhat waits for a person
pythonrestart, shutdownbefore_lifecycle() finishes the product's work, then carry_out() starts the program again in place, or ends itA 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-noderestart, shutdownbeforeLifecycle(), then carryOut() starts a new process and ends the old oneA 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-fullrestart, 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 IDLanguageForStatus
heart/embeddedstandard/esp32-full/v1.2611C99 core + ESP-IDF 5.2 portESP32, ESP32-S3, ESP32-C3, ESP32-C6Core 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.

TemplateLanguageForWhy it matters
rust-heart-coreRust + the heart-core crateEmbedded LinuxHEART Full from the reference implementation: approvals, Valve, custom commands
browser-workerJavaScript + heart-core WASMWeb appsFull HEART in a browser tab
docker-sidecarContainer running heartdKubernetes, DockerAdd HEART to any service without touching its code
cpp-posixC++17Embedded Linux, Qt devicesMany product teams work in C++
csharp-dotnetC# (.NET 8)Windows, industrial PCs
kotlin-androidKotlinAndroid apps and devices
swiftSwiftiOS, macOS
dart-flutterDartFlutter apps
typescript-denoTypeScriptDeno, Bun, edge
elixirElixir / ErlangNerves devices, telecom
lua-openwrtLuaOpenWrt routers, NodeMCU
rust-embedded-nostdRust no_stdCortex-M, RISC-V, ESP32
zephyrC (Zephyr module)Zephyr boards
freertosC (FreeRTOS task)FreeRTOS microcontrollers
zigZigEmbedded and systems
ada-sparkAda / SPARKRail, avionics, defenceOutside the safety function only
iec61131-stIEC 61131-3 Structured TextPLCs (CODESYS, TwinCAT, Siemens)Factory controllers, on the supervisory side only
asm-avrAVR assemblyATmega, ATtinyThe smallest 8-bit chips
asm-xtensaXtensa assemblyESP32 (original), ESP8266
mqtt-deviceC + MQTT 5Devices already using MQTTMust 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.
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#

ToolWhat it does
tools/heart_signals.pyDrafts 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.pyFinds HEART systems on a local network (_heart._tcp), or announces one from its public Card. See Part 4, Section 3.4.
tools/avahi/heart.serviceAnnounces a Linux device through Avahi. Copy it to /etc/avahi/services/.
tools/test_templates.py, tools/build_catalog.pyTest every template, and build the catalog
tools/test_full_starter.pyTests 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.pyTests 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 productUse
An app or service on Linux, macOS or WindowsThe 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 commandsesp32-full
A microcontroller with a serial portc-baremetal, or micropython, arduino, or an assembly port, plus the bridge
A web page or a plug-in hostwasm-wat
A product that must approve actions, filter private data or run custom commandsNot a template: use heart-core-rs (HEART Full)

8. Downloading#

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

EndpointGives
GET /v1/templatesThe catalog: every template, its ID, version and test result
GET /v1/templates/{name}One template's details
GET /v1/templates/{name}/{version}.zipThe template as a zip, with the bridge included for device templates

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