Distributed by design. Data-driven by default.
AimDB turns data contracts into the architecture. Define your schemas once and deploy them unchanged across microcontrollers, edge gateways, Kubernetes and the browser, with explicit, typed migrations when the contract evolves.
AimDB is not a storage engine. It's a typed data plane where the Rust type is the wire format.
See it running → Live weather stations streaming typed contracts across MCU, edge and cloud.
Ask your AI about it → Query the live weather mesh in natural language. No install required.
Most of a distributed system's complexity is translation: IDLs, codegen, serialization glue, schema registries. AimDB deletes that layer by making the Rust type the contract — defined once, compiled unchanged from a no_std microcontroller to the browser.
- One type, every tier. The same struct compiles for firmware and cloud. No conversion layer between them.
- The buffer defines how data moves. No manual queue wiring, no separate transport config.
- No untyped boundaries. Capabilities, like streaming, migration, observability and connectors, are unlocked by traits.
None of this is roadmap. Every claim is backed by code, tests or committed benchmarks:
- Data contracts as schema → the Rust type is the wire contract. No IDL, no codegen, CI cross-compiles unchanged from Cortex-M to WASM.
- Typed data migrations →
migration_chain!const-validates the chain and worksno_std, so old and new nodes coexist on the wire. - Zero allocation per message → allocation baselines across Tokio, Embassy and WASM.
- Non-blocking producers → synchronous
produce()calls and overwrite semantics on all buffers. - Identical buffer contracts across runtimes → shared conformance suite validates SPMC Ring, SingleLatest and Mailbox on every adapter.
The Next Era of Software Architecture Is Data-First
cargo new my-aimdb-app && cd my-aimdb-app
cargo add aimdb-core aimdb-tokio-adapter
cargo add tokio --features fullDrop this into src/main.rs:
use aimdb_core::{buffer::BufferCfg, AimDbBuilder};
use aimdb_tokio_adapter::{TokioAdapter, TokioRecordRegistrarExt};
use std::sync::Arc;
#[derive(Clone, Debug)]
pub struct Temperature {
pub celsius: f32,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let runtime = Arc::new(TokioAdapter::new()?);
let mut builder = AimDbBuilder::new().runtime(runtime);
builder.configure::<Temperature>("temp.indoor", |reg| {
reg.buffer(BufferCfg::SpmcRing { capacity: 16 })
.source(|ctx, producer| async move {
let time = ctx.time();
for celsius in [21.0, 22.5, 24.1] {
producer.produce(Temperature { celsius });
time.sleep_secs(1).await;
}
})
.tap(|ctx, consumer| async move {
let mut reader = consumer.subscribe();
while let Ok(t) = reader.recv().await {
ctx.log().info(&format!("temp: {:.1}°C", t.celsius));
}
});
});
// Build the db and drive every source/tap future until shutdown.
builder.run().await?;
Ok(())
}cargo run — three temperature readings stream through a typed pipeline. The same code compiles for Embassy on a Cortex-M4 or WASM in the browser by swapping the runtime adapter.
A full MCU → edge → cloud mesh: three weather stations, MQTT broker and a central hub.
git clone https://github.com/aimdb-dev/aimdb
cd aimdb/examples/weather-mesh-demo
docker compose upThree buffer primitives that cover most data-movement patterns:
| Buffer | Semantics | Use cases |
|---|---|---|
| SPMC Ring | Bounded stream with independent consumers | Sensor telemetry, event logs |
| SingleLatest | Only the current value matters | Feature flags, config, UI state |
| Mailbox / async Mailbox | Latest instruction wins | Device commands, actuation, RPC |
One async API across runtimes. Tokio, Embassy, WASM — swap the runtime adapter, keep the code. → How the runtime abstraction works
Connectors that ship today: MQTT, KNX, WebSocket, TCP, serial (COBS-framed UART) and Unix domain sockets. Writing your own is one trait impl. → Connector status
Optional persistence. The core is an in-memory data plane; aimdb-persistence adds .persist() with a SQLite backend (aimdb-persistence-sqlite) for records whose history must survive restarts.
Deep dives: source/tap/transform · schema migration · reactive pipelines
Every capability is an opt-in trait on your schema type: implement it and exactly one method appears on the registrar.
| Contract | Implement when… | Verb it unlocks | Tier |
|---|---|---|---|
Linkable |
the record is mirrored to/from an endpoint (MQTT, KNX, serial, UDS…) | .linked_from(url) / .linked_to(url) (#[derive(Linkable)] for JSON) |
wire (prod) |
Streamable |
the record streams to browsers as schema-named JSON | ws-connector .register::<T>() |
wire (prod) |
Migratable |
the schema evolved across versions | migration_chain! |
wire (prod) |
Settable |
sync code outside AimDB sets the value | SyncProducer::set_value(v) |
wire (prod) |
Observable |
the value is worth watching in production | .observe() → live last/min/max/mean on record.list/record.get |
introspection (prod, optional) |
Simulatable |
the type can generate realistic synthetic data | .simulate(profile, rng) |
dev-only — never ships in prod |
Simulatable is the odd one out: it lives behind the simulatable feature (never a default) and switching from simulated to real data is one #[cfg] in your app:
builder.configure::<Temperature>(KEY, |reg| {
#[cfg(feature = "sim")]
reg.simulate(profile, rng);
#[cfg(not(feature = "sim"))]
reg.source(read_hardware);
});Build with sim off and the simulation code is gone — no T::simulate impls, no rand, nothing to audit.
Old and new nodes coexist. Migration steps are typed and bidirectional and migration_chain! checks the whole chain at compile time — roundtrip tests cover upgrade and downgrade across multi-step chains. It's no_std too: even an MCU can accept a payload one schema version behind or downgrade its output for an older peer.
Deep dive: data contracts
A record is written by a Source, lands in a typed Buffer and fans out to in-process subscribers (Tap) and wire-format bridges (Link → connector):
Producer Consumers
──────── ─────────
┌──────────────┐ ───► Tap (in-process subscriber)
Source ───► │ Buffer │
(typed) │ SPMC / SL / │ ───► Tap (another subscriber)
│ Mailbox │
└──────────────┘ ───► Link ──► MQTT / KNX / WS / UDS / serial
Types check correctness at compile time, buffers enforce flow semantics at runtime and connectors bridge to your infrastructure, with no integration layer in between. The same code compiles for MCU, edge, cloud or browser — see Platform Support below.
AimDB ships an MCP server. Point any MCP-compatible client at a running instance and query it in natural language.
Try it against the live demo — no install required. Add this to your workspace:
.vscode/mcp.json:
{
"servers": {
"aimdb-weather": {
"type": "http",
"url": "http://aimdb.dev/mcp"
}
}
}Then ask: "What's the current temperature in Munich?"
See the MCP server docs for Claude Desktop and other editors or read the deep dive: AI-Assisted System Introspection: AimDB Meets the Model Context Protocol.
- Quick Start Guide — dependencies, platform setup, your first contract
- API reference (docs.rs) — full Rust API
- Blog — design notes, deep dives, release write-ups
- Live demo — running sensor mesh
| Protocol | Status | Runtimes |
|---|---|---|
MQTT — aimdb-mqtt-connector |
✅ Ready | std, no_std |
KNX — aimdb-knx-connector |
✅ Ready | std, no_std |
WebSocket — aimdb-websocket-connector |
✅ Ready | std, wasm |
TCP — aimdb-tcp-connector |
✅ Ready | std, no_std |
| Kafka | 📋 Planned | std |
| Modbus | 📋 Planned | std, no_std |
The serial, TCP and UDS connectors carry both record mirroring and the AimX remote-access protocol used by the CLI and MCP server. Typed records over multiple transports, from bare metal to cloud.
| Target | Runtime | Adapter | Features | Footprint |
|---|---|---|---|---|
| ARM Cortex-M (STM32H5, STM32F4) | Embassy | aimdb-embassy-adapter |
no_std, async | ~50KB+ |
| Linux Edge (RPi, gateways) | Tokio | aimdb-tokio-adapter |
Full std | ~10MB+ |
| Containers / K8s | Tokio | aimdb-tokio-adapter |
Full std | ~10MB+ |
| Browser / SPA | WASM | aimdb-wasm-adapter |
wasm32, single-threaded | ~2MB+ |
We're a small team building something ambitious. The fastest way to help is to take on a scoped piece of it. Each of these is sized for a few hours and includes file pointers, acceptance criteria and a place to ask questions:
- #93 — Minimal example:
hello-single-latest· 2–3h · docs - #101 — Minimal example:
hello-spmc-ring-async· 2–3h · docs
Comment on an issue if you'd like to take it — we respond within a day. New ideas welcome on Discussions.
Found a bug or want a feature? Open a GitHub issue.
Have questions or ideas? Join the discussion on GitHub Discussions.
See the contributing guide for build, test and style requirements.
Distributed by design. Data-driven by default.
Get started · Live demo · Join the discussion

