Open source · Rust · BDEW EDI@Energy FV2026-04-01 · FV2026-10-01

German energy-market operations,
from raw EDIFACT to production — in Rust.

Open-source, full-stack German energy-market operations platform in Rust: BDEW MaKo / EDI@Energy market communication across every Prüfidentifikator in the catalogue, an event-sourced process runtime, NNE/EEG settlement, retail billing, AS4 transport and BO4E integration — every regulated process as a correct, auditable workflow.

458Prüfidentifikatoren routed
63MaKo workflows
17EDIFACT message types
17services
4market roles (NB·LF·MSB·ESA)

What happens to a message

A market partner sends an interchange over AS4. Everything after that is the same path for every process — parse, validate against the AHB in force on that date, route to a workflow, and answer inside the Frist.

graph LR
    MP["Marktpartner"]
    AS4["AS4 / ebMS3
sign · encrypt · receipt"] VAL["Parse + validate
MIG · AHB · semantic"] WF["Workflow
event-sourced, replayable"] FRIST["Frist
BDEW Werktag calendar"] OUT["Outbox
persist before dispatch"] ERP["ERP · CloudEvents"] MP -->|"UTILMD · MSCONS · ORDERS · INVOIC"| AS4 AS4 --> VAL VAL -->|"Prüfidentifikator"| WF WF --> FRIST WF --> OUT OUT -->|"answer interchange"| AS4 OUT --> ERP AS4 -->|"CONTRL / APERAK"| MP

The format layer is generated from the BDEW profiles, so an annual release is a codegen run rather than a rewrite. The domain layer never sees EDIFACT: it receives typed commands and emits typed events.

Two numbers describe the same catalogue from different sides: 458 Prüfidentifikatoren are routed to a workflow, and 349 additionally carry validated AHB segment rules. The gap is a declared set of routed-without-rules PIDs, not an accident — and a release that would shrink either number fails the build.

What it looks like

The format layer stands alone. Add one crate and an interchange becomes a typed message, validated against the AHB profile in force on its date.

use edi_energy::{EdiEnergyMessage, Platform};

let msg = Platform::with_all_profiles().parse(wire)?;

msg.try_message_type();            // Some(Utilmd)
msg.detect_release()?.as_str();    // "S2.1"
msg.detect_pruefidentifikator()?;  // 55001 — Anmeldung Lieferbeginn

let report = msg.validate()?;      // MIG + AHB + semantic
report.is_valid();                 // true

An unregistered Prüfidentifikator is reported, never silently accepted — and the profile is chosen by the message's own date, because two Formatversionen can share one wire release code and only the date tells them apart.

The shape of the platform

Seventeen services along one path: transport and protocol at the edge, master data in the middle, settlement and billing at the end — each owning its own data, talking over typed REST and CloudEvents.

graph TB
    subgraph edge["Edge — protocol"]
      MAKOD["makod
AS4 · EDIFACT · workflows"] PROCESSD["processd
STP decisions"] end subgraph core["Core — market data"] MARKTD["marktd
BO4E hub · fan-out"] VERTRAGD["vertragd · productd
contracts · products"] EDMD["edmd
metering · SMGW"] end subgraph money["Settlement and billing"] NETZ["netzbilanzd
NNE · MMM"] EINSD["einsd
EEG · KWKG"] BILLINGD["billingd · invoicd
retail · EN 16931"] ACCT["accountingd
FI-CA ledger"] end subgraph ops["Operations"] OBSD["obsd
BNetzA KPIs · Fristen"] AGENTD["agentd
AI specialists"] PORTALD["portald
customer portal"] end PROCESSD --> MAKOD MAKOD --> MARKTD MARKTD --> VERTRAGD MARKTD --> EDMD EDMD --> NETZ EDMD --> EINSD EDMD --> BILLINGD VERTRAGD --> BILLINGD NETZ --> ACCT BILLINGD --> ACCT EINSD --> ACCT PORTALD --> BILLINGD OBSD -.->|"watches"| MAKOD AGENTD -.->|"MCP reads"| MARKTD AGENTD -.->|"MCP reads"| OBSD

What you get

Protocol & process

Parse, validate and build all 17 EDI@Energy EDIFACT types; run every MaKo process as an event-sourced, replayable workflow over AS4/ebMS3 — BDEW AS4-Profil, sign and encrypt, signed receipts, retry with duplicate elimination.

makod · processd →

Market data

A typed BO4E market-data hub — MaLo/MeLo, contracts, supply status, device configuration, grid-operator registry — with durable CloudEvents fan-out and OIDC/JWT on every route.

marktd · vertragd · productd →

Metering & settlement

Quarter-hourly metering with §60 MsbG substitute values and SMGW lifecycle; role-neutral grid settlement (NNE/MMM/MSB), EEG/KWKG feed-in and MaBiS Summenzeitreihen — each position carrying a legal-reference calculation trace.

edmd · netzbilanzd · einsd →

Billing & ledger

Retail billing with EN 16931 e-invoicing (XRechnung, ZUGFeRD), SEPA collection and returns, and a hash-chained FI-CA ledger with § 147 AO period seals and Merkle inclusion proofs.

billingd · invoicd · accountingd →

Operations & oversight

BNetzA KPI observability with Fristen tracking, a customer portal, and an agent plane over the 163 MCP tools the platform exposes — 28 declarative specialists whose every model and tool call is a journaled effect, advisory by construction, with a four-eyes worklist in front of anything that acts.

obsd · portald · agentd →

Testable from Python

makotest binds the same Rust core the platform runs — BDEW check digits, the Werktag calendar, the published answer Fristen, EDIFACT build and AHB validation — so a test and production can never disagree about what “valid” means, nor about when a Frist expires.

makotest →

Built for the regulatory pace

German market communication moves fast — LFW24, §14a, §41a dynamic tariffs, §42b/c energy sharing, the EDIFACT→API transition, the MaBiS-Hub cutover. mako’s domain layer is deliberately split from transport and format, so when the market moves, the platform moves with a codegen run — not a rewrite.

  • Auditable by construction — event-sourced processes, replayable state, hash-chained ledger with § 147 AO period seals.
  • Every regulated process modeled, for every market role — and a role-scoped build contains only its own arm's code.
  • Validation that fails loudly — an unregistered Prüfidentifikator is reported, never quietly accepted.
  • Fristen that agree with each other — one BDEW Werktag calendar, from the APERAK clock to an agent's approval window.
  • Readable, verifiable, extensible — source you can audit and run.

Start in minutes

# Parse & validate an EDIFACT interchange
cargo add edi-energy

# Run the protocol daemon
docker run --rm -p 8080:8080 \
  ghcr.io/hupe1980/makod:latest

# Drive it from Python — generators, simulators, pytest plugin
pip install makotest

Full getting-started guide →