tag:github.com,2008:https://github.com/aimdb-dev/aimdb/releases
Release notes from aimdb
2026-03-16T21:24:57Z
tag:github.com,2008:Repository/1061389408/v1.0.0
2026-03-16T21:49:11Z
v1.0.0
<h1>AimDB v1.0.0 Release Notes</h1>
<p><strong>Stable core API, real-time browser streaming, and LLM-driven architecture design!</strong></p>
<blockquote>
<p>Async in-memory database for MCU β edge β cloud data synchronization</p>
</blockquote>
<hr>
<h2>π― Highlights</h2>
<p>This release promotes <strong><code>aimdb-core</code> to 1.0.0</strong> β declaring a stable public API for the core database engine. It also ships four entirely new crates: a <strong>WebSocket connector</strong> for real-time browser streaming, a <strong>WASM adapter</strong> for running AimDB in the browser, a <strong>code generation library</strong> for architecture-to-code workflows, and a <strong>shared wire protocol</strong> for the WebSocket ecosystem. The MCP server gains a full <strong>architecture agent</strong> for LLM-driven system design, and the CLI adds <strong>code generation</strong> and <strong>live monitoring</strong> commands.</p>
<p><strong>Headline: MCU β Edge β Cloud β Browser</strong> β AimDB now spans the full stack.</p>
<p><strong>Extensible Streamable registry</strong> β the <code>Streamable</code> type dispatch system has been redesigned from a closed dispatcher to an open, extensible registry pattern. Users now register their own types via <code>.register::<T>()</code> on connector and adapter builders. Concrete contracts (Temperature, Humidity, GpsLocation) have moved to application-level crates.</p>
<hr>
<h2>β¨ Major Features</h2>
<h3>π WebSocket Connector (New Crate)</h3>
<p><strong>Real-time bidirectional streaming to browsers and between AimDB instances!</strong></p>
<div class="highlight highlight-source-rust notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="use aimdb_tokio_adapter::TokioAdapter;
use aimdb_websocket_connector::WebSocketConnector;
let db = AimDbBuilder::new()
.runtime(TokioAdapter::new())
.with_connector(
WebSocketConnector::new()
.bind("0.0.0.0:8080")
.path("/ws")
.with_late_join(true),
);
// Push records to browser clients
builder.configure::<Temperature>(AppKey::Temp, |reg| {
reg.buffer(BufferCfg::SingleLatest)
.link_to("ws://temperature"); // β streams to all subscribers
});"><pre><span class="pl-k">use</span> aimdb_tokio_adapter<span class="pl-kos">::</span><span class="pl-v">TokioAdapter</span><span class="pl-kos">;</span>
<span class="pl-k">use</span> aimdb_websocket_connector<span class="pl-kos">::</span><span class="pl-v">WebSocketConnector</span><span class="pl-kos">;</span>
<span class="pl-k">let</span> db = <span class="pl-smi">AimDbBuilder</span><span class="pl-kos">::</span><span class="pl-en">new</span><span class="pl-kos">(</span><span class="pl-kos">)</span>
<span class="pl-kos">.</span><span class="pl-en">runtime</span><span class="pl-kos">(</span><span class="pl-smi">TokioAdapter</span><span class="pl-kos">::</span><span class="pl-en">new</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span>
<span class="pl-kos">.</span><span class="pl-en">with_connector</span><span class="pl-kos">(</span>
<span class="pl-smi">WebSocketConnector</span><span class="pl-kos">::</span><span class="pl-en">new</span><span class="pl-kos">(</span><span class="pl-kos">)</span>
<span class="pl-kos">.</span><span class="pl-en">bind</span><span class="pl-kos">(</span><span class="pl-s">"0.0.0.0:8080"</span><span class="pl-kos">)</span>
<span class="pl-kos">.</span><span class="pl-en">path</span><span class="pl-kos">(</span><span class="pl-s">"/ws"</span><span class="pl-kos">)</span>
<span class="pl-kos">.</span><span class="pl-en">with_late_join</span><span class="pl-kos">(</span><span class="pl-c1">true</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
<span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-c">// Push records to browser clients</span>
builder<span class="pl-kos">.</span><span class="pl-en">configure</span><span class="pl-kos">::</span><span class="pl-kos"><</span><span class="pl-smi">Temperature</span><span class="pl-kos">></span><span class="pl-kos">(</span><span class="pl-smi">AppKey</span><span class="pl-kos">::</span><span class="pl-v">Temp</span><span class="pl-kos">,</span> |reg| <span class="pl-kos">{</span>
reg<span class="pl-kos">.</span><span class="pl-en">buffer</span><span class="pl-kos">(</span><span class="pl-smi">BufferCfg</span><span class="pl-kos">::</span><span class="pl-v">SingleLatest</span><span class="pl-kos">)</span>
<span class="pl-kos">.</span><span class="pl-en">link_to</span><span class="pl-kos">(</span><span class="pl-s">"ws://temperature"</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// β streams to all subscribers</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<p><strong>Two modes:</strong></p>
<ul>
<li>π₯οΈ <strong>Server mode</strong> (Axum-based) β accept incoming WebSocket connections via <code>link_to("ws://topic")</code></li>
<li>π <strong>Client mode</strong> (tokio-tungstenite) β connect out to remote servers via <code>link_to("ws-client://host/topic")</code> for AimDB-to-AimDB sync without a broker</li>
<li>π <strong>Authentication</strong> via pluggable <code>AuthHandler</code> trait</li>
<li>π‘ <strong>MQTT-style wildcards</strong> β <code>#</code> multi-level, <code>*</code> single-level topic matching</li>
<li>β±οΈ <strong>Late-join</strong> β new subscribers receive current values immediately</li>
<li>π <strong><code>StreamableRegistry</code></strong> β extensible type-erased dispatch via <code>.register::<T>()</code> with schema-name collision detection</li>
</ul>
<h3>πΈοΈ WASM Adapter (New Crate)</h3>
<p><strong>Run AimDB in the browser β full dataflow engine via WebAssembly!</strong></p>
<div class="highlight highlight-source-tsx notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="import { useRecord, useBridge } from 'aimdb-wasm-adapter/react';
function TemperatureDashboard() {
const bridge = useBridge("ws://localhost:8080/ws");
const temp = useRecord<Temperature>(bridge, "sensor.temperature");
return <div>Current: {temp?.celsius}Β°C</div>;
}"><pre><span class="pl-k">import</span> <span class="pl-kos">{</span> <span class="pl-s1">useRecord</span><span class="pl-kos">,</span> <span class="pl-s1">useBridge</span> <span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'aimdb-wasm-adapter/react'</span><span class="pl-kos">;</span>
<span class="pl-k">function</span> <span class="pl-v">TemperatureDashboard</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
<span class="pl-k">const</span> <span class="pl-s1">bridge</span> <span class="pl-c1">=</span> <span class="pl-en">useBridge</span><span class="pl-kos">(</span><span class="pl-s">"ws://localhost:8080/ws"</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-k">const</span> <span class="pl-s1">temp</span> <span class="pl-c1">=</span> <span class="pl-en">useRecord</span><span class="pl-c1"><</span><span class="pl-smi">Temperature</span><span class="pl-c1">></span><span class="pl-kos">(</span><span class="pl-s1">bridge</span><span class="pl-kos">,</span> <span class="pl-s">"sensor.temperature"</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-k">return</span> <span class="pl-c1"><</span><span class="pl-s1">div</span><span class="pl-c1">></span>Current: <span class="pl-kos">{</span><span class="pl-s1">temp</span><span class="pl-kos">?.</span><span class="pl-c1">celsius</span><span class="pl-kos">}</span>Β°C<span class="pl-kos"></</span><span class="pl-s1">div</span><span class="pl-c1">></span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p><strong>Features:</strong></p>
<ul>
<li>ποΈ Full <code>aimdb-executor</code> trait implementations (<code>RuntimeAdapter</code>, <code>Spawn</code>, <code>TimeOps</code>, <code>Logger</code>)</li>
<li>πͺΆ <code>Rc<RefCell<β¦>></code> buffers β zero-overhead for single-threaded WASM</li>
<li>π― <code>WasmDb</code> facade via <code>#[wasm_bindgen]</code>: <code>configureRecord</code>, <code>get</code>, <code>set</code>, <code>subscribe</code></li>
<li>π <code>WsBridge</code> β WebSocket bridge connecting browser to remote AimDB server</li>
<li>βοΈ React hooks: <code>useRecord<T></code>, <code>useSetRecord<T></code>, <code>useBridge</code></li>
<li>π <code>SchemaRegistry</code> for type-erased record dispatch with extensible <code>.register::<T>()</code> API</li>
<li><code>no_std</code> + <code>alloc</code> compatible (<code>wasm32-unknown-unknown</code> target)</li>
</ul>
<h3>π Data Contracts β Pure Trait Crate</h3>
<p><strong><code>aimdb-data-contracts</code> refocused as a pure trait-definition crate (version reset to 0.1.0).</strong></p>
<p>Trait definitions for self-describing data schemas that work identically across MCU, edge, and cloud:</p>
<ul>
<li><code>SchemaType</code> β unique identity and versioning</li>
<li><code>Streamable</code> β capability marker for types crossing serialization boundaries</li>
<li><code>Linkable</code> β wire format for connector transport</li>
<li><code>Simulatable</code> β test data generation</li>
<li><code>Observable</code> β signal extraction for monitoring</li>
<li><code>Migratable</code> β schema evolution with <code>MigrationChain</code> and <code>MigrationStep</code></li>
</ul>
<p>Concrete contracts (Temperature, Humidity, GpsLocation) and the closed <code>StreamableVisitor</code> dispatcher have been removed β see <a href="#%EF%B8%8F-breaking-changes">Breaking Changes</a> below.</p>
<h3>ποΈ Code Generation (New Crate)</h3>
<p><strong>Architecture-to-code: generate Rust source and Mermaid diagrams from <code>.aimdb/state.toml</code>!</strong></p>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="# Generate Mermaid architecture diagram
aimdb generate mermaid
# Generate Rust schema code
aimdb generate schema
# Scaffold a new common crate
aimdb generate common-crate
# Scaffold a hub binary crate
aimdb generate hub-crate"><pre><span class="pl-c"><span class="pl-c">#</span> Generate Mermaid architecture diagram</span>
aimdb generate mermaid
<span class="pl-c"><span class="pl-c">#</span> Generate Rust schema code</span>
aimdb generate schema
<span class="pl-c"><span class="pl-c">#</span> Scaffold a new common crate</span>
aimdb generate common-crate
<span class="pl-c"><span class="pl-c">#</span> Scaffold a hub binary crate</span>
aimdb generate hub-crate</pre></div>
<p><strong><code>aimdb-codegen</code> features:</strong></p>
<ul>
<li>π <code>ArchitectureState</code> type for reading <code>.aimdb/state.toml</code> decision records</li>
<li>π Mermaid diagram generation from architecture state</li>
<li>π¦ Rust source generation β value structs, key enums, <code>SchemaType</code>/<code>Linkable</code> impls, <code>configure_schema()</code> functions</li>
<li>ποΈ Common crate, hub crate, and binary crate scaffolding</li>
<li>β
State validation module for architecture integrity checks</li>
</ul>
<h3>π€ Architecture Agent (MCP)</h3>
<p><strong>LLM-driven system design β propose, validate, and apply architecture changes through conversation!</strong></p>
<p>The MCP server now includes a full architecture agent with a session state machine:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Idle β Gathering β Proposing β Resolve"><pre class="notranslate"><code>Idle β Gathering β Proposing β Resolve
</code></pre></div>
<p><strong>16+ new MCP tools:</strong></p>
<table>
<thead>
<tr>
<th>Tool</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>propose_add_record</code></td>
<td>Add a new record to the architecture</td>
</tr>
<tr>
<td><code>propose_add_connector</code></td>
<td>Add a connector (MQTT, WebSocket, etc.)</td>
</tr>
<tr>
<td><code>propose_modify_buffer</code></td>
<td>Change buffer type/capacity</td>
</tr>
<tr>
<td><code>propose_modify_fields</code></td>
<td>Modify record fields</td>
</tr>
<tr>
<td><code>propose_modify_key_variants</code></td>
<td>Change key variants</td>
</tr>
<tr>
<td><code>remove_record</code></td>
<td>Remove a record</td>
</tr>
<tr>
<td><code>rename_record</code></td>
<td>Rename a record</td>
</tr>
<tr>
<td><code>reset_session</code></td>
<td>Reset agent session state</td>
</tr>
<tr>
<td><code>resolve_proposal</code></td>
<td>Apply or reject pending proposals</td>
</tr>
<tr>
<td><code>save_memory</code></td>
<td>Persist architecture decisions</td>
</tr>
<tr>
<td><code>validate_against_instance</code></td>
<td>Validate architecture against running instance</td>
</tr>
<tr>
<td><code>get_architecture</code></td>
<td>Get current architecture state</td>
</tr>
<tr>
<td><code>get_buffer_metrics</code></td>
<td>Get buffer performance metrics</td>
</tr>
</tbody>
</table>
<p>Architecture MCP resources provide Mermaid diagrams and validation results as live resources.</p>
<h3>π‘ Wire Protocol (New Crate)</h3>
<p><strong>Shared wire protocol types for the WebSocket ecosystem.</strong></p>
<p><code>aimdb-ws-protocol</code> provides <code>ServerMessage</code> and <code>ClientMessage</code> enums used by both the WebSocket connector (server side) and the WASM adapter (browser side). JSON-encoded with <code>"type"</code> discriminant tag.</p>
<hr>
<h2>π§ Other Changes</h2>
<h3>aimdb-core</h3>
<ul>
<li>Added <code>ws://</code> and <code>wss://</code> URL scheme support in <code>ConnectorUrl</code> for WebSocket connectors</li>
<li><code>ConnectorUrl::default_port()</code> now handles WebSocket schemes</li>
<li><code>ConnectorUrl::is_secure()</code> includes <code>wss://</code></li>
</ul>
<h3>aimdb-cli</h3>
<ul>
<li>New <code>aimdb generate</code> subcommand for code generation via <code>aimdb-codegen</code></li>
<li>New <code>aimdb watch</code> subcommand for live record monitoring</li>
</ul>
<h3>Dependency Updates</h3>
<ul>
<li><strong>aimdb-knx-connector</strong> <code>0.3.1</code> β Updated Embassy dependency versions (executor 0.10.0, time 0.5.1, sync 0.8.0, futures 0.1.2, net 0.9.0)</li>
<li><strong>aimdb-mqtt-connector</strong> <code>0.5.1</code> β Updated Embassy dependency versions (executor 0.10.0, time 0.5.1, sync 0.8.0, net 0.9.0)</li>
<li>Embassy submodules updated to latest upstream commits</li>
</ul>
<hr>
<h2>π¦ Published Crates</h2>
<h3>New Crates</h3>
<ul>
<li>π <code>[email protected]</code> β real-time bidirectional WebSocket streaming</li>
<li>π <code>[email protected]</code> β shared wire protocol types</li>
<li>π <code>[email protected]</code> β WebAssembly runtime adapter with React hooks</li>
<li>π <code>[email protected]</code> β architecture-to-code generation</li>
</ul>
<h3>Updated</h3>
<table>
<thead>
<tr>
<th>Crate</th>
<th>Previous</th>
<th>New</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>aimdb-core</code></td>
<td>0.5.0</td>
<td><strong>1.0.0</strong></td>
</tr>
<tr>
<td><code>aimdb-data-contracts</code></td>
<td>0.5.0</td>
<td><strong>0.1.0</strong> (reset β pure trait crate)</td>
</tr>
<tr>
<td><code>aimdb-cli</code></td>
<td>0.5.0</td>
<td><strong>0.6.0</strong></td>
</tr>
<tr>
<td><code>aimdb-mcp</code></td>
<td>0.5.0</td>
<td><strong>0.6.0</strong></td>
</tr>
<tr>
<td><code>aimdb-mqtt-connector</code></td>
<td>0.5.0</td>
<td><strong>0.5.1</strong></td>
</tr>
<tr>
<td><code>aimdb-knx-connector</code></td>
<td>0.3.0</td>
<td><strong>0.3.1</strong></td>
</tr>
</tbody>
</table>
<h3>Unchanged</h3>
<ul>
<li><code>[email protected]</code></li>
<li><code>[email protected]</code></li>
<li><code>[email protected]</code></li>
<li><code>[email protected]</code></li>
<li><code>[email protected]</code></li>
<li><code>[email protected]</code></li>
<li><code>[email protected]</code></li>
<li><code>[email protected]</code></li>
</ul>
<hr>
<h2><g-emoji class="g-emoji" alias="warning">β οΈ</g-emoji> Breaking Changes</h2>
<ul>
<li><strong>aimdb-data-contracts</strong>: Concrete contracts removed from this crate. If you depended on <code>Temperature</code>, <code>Humidity</code>, or <code>GpsLocation</code> from <code>aimdb-data-contracts</code>, define them in your own application crate or shared common crate (see <code>examples/weather-mesh-demo/weather-mesh-common</code> for a reference).</li>
<li><strong>aimdb-data-contracts</strong>: <code>for_each_streamable()</code> and <code>StreamableVisitor</code> removed. Use <code>.register::<T>()</code> on connector/adapter builders instead.</li>
<li><strong>aimdb-data-contracts</strong>: <code>ts</code> feature removed (<code>ts-rs</code> dependency dropped).</li>
<li><strong>aimdb-data-contracts</strong>: Version reset from 1.0.0 to 0.1.0 to reflect the reduced, stabilizing scope as a pure trait crate.</li>
</ul>
<hr>
<h2>π₯οΈ New CLI Commands</h2>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="# Code generation
aimdb generate mermaid # Generate Mermaid architecture diagram
aimdb generate schema # Generate Rust schema code
aimdb generate common-crate # Scaffold a common crate
aimdb generate hub-crate # Scaffold a hub binary crate
# Live monitoring
aimdb watch <record> # Watch live record updates"><pre><span class="pl-c"><span class="pl-c">#</span> Code generation</span>
aimdb generate mermaid <span class="pl-c"><span class="pl-c">#</span> Generate Mermaid architecture diagram</span>
aimdb generate schema <span class="pl-c"><span class="pl-c">#</span> Generate Rust schema code</span>
aimdb generate common-crate <span class="pl-c"><span class="pl-c">#</span> Scaffold a common crate</span>
aimdb generate hub-crate <span class="pl-c"><span class="pl-c">#</span> Scaffold a hub binary crate</span>
<span class="pl-c"><span class="pl-c">#</span> Live monitoring</span>
aimdb watch <span class="pl-k"><</span>record<span class="pl-k">></span> <span class="pl-c"><span class="pl-c">#</span> Watch live record updates</span></pre></div>
<hr>
<h2>π Migration Guide</h2>
<h3>Step 1: Update dependencies</h3>
<div class="highlight highlight-source-toml notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="[dependencies]
aimdb-core = "1.0"
aimdb-data-contracts = "0.1" # reset β now a pure trait crate
aimdb-tokio-adapter = "0.5" # unchanged
# Optional: add WebSocket streaming
aimdb-websocket-connector = "0.1"
# Optional: add WASM support
aimdb-wasm-adapter = "0.1""><pre>[<span class="pl-en">dependencies</span>]
<span class="pl-smi">aimdb-core</span> = <span class="pl-s"><span class="pl-pds">"</span>1.0<span class="pl-pds">"</span></span>
<span class="pl-smi">aimdb-data-contracts</span> = <span class="pl-s"><span class="pl-pds">"</span>0.1<span class="pl-pds">"</span></span> <span class="pl-c"><span class="pl-c">#</span> reset β now a pure trait crate</span>
<span class="pl-smi">aimdb-tokio-adapter</span> = <span class="pl-s"><span class="pl-pds">"</span>0.5<span class="pl-pds">"</span></span> <span class="pl-c"><span class="pl-c">#</span> unchanged</span>
<span class="pl-c"><span class="pl-c">#</span> Optional: add WebSocket streaming</span>
<span class="pl-smi">aimdb-websocket-connector</span> = <span class="pl-s"><span class="pl-pds">"</span>0.1<span class="pl-pds">"</span></span>
<span class="pl-c"><span class="pl-c">#</span> Optional: add WASM support</span>
<span class="pl-smi">aimdb-wasm-adapter</span> = <span class="pl-s"><span class="pl-pds">"</span>0.1<span class="pl-pds">"</span></span></pre></div>
<h3>Step 2: Move concrete contracts to your crate</h3>
<p>If you used <code>Temperature</code>, <code>Humidity</code>, or <code>GpsLocation</code> from <code>aimdb-data-contracts</code>, copy them into your own application or shared common crate. See <code>examples/weather-mesh-demo/weather-mesh-common</code> for a working example.</p>
<h3>Step 3: Replace <code>StreamableVisitor</code> with <code>.register::<T>()</code></h3>
<div class="highlight highlight-source-rust notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="// Before (closed dispatcher):
// for_each_streamable(visitor);
// After (extensible registry):
let connector = WebSocketConnector::new()
.register::<Temperature>()
.register::<Humidity>()
.register::<GpsLocation>();"><pre><span class="pl-c">// Before (closed dispatcher):</span>
<span class="pl-c">// for_each_streamable(visitor);</span>
<span class="pl-c">// After (extensible registry):</span>
<span class="pl-k">let</span> connector = <span class="pl-smi">WebSocketConnector</span><span class="pl-kos">::</span><span class="pl-en">new</span><span class="pl-kos">(</span><span class="pl-kos">)</span>
<span class="pl-kos">.</span><span class="pl-en">register</span><span class="pl-kos">::</span><span class="pl-kos"><</span><span class="pl-smi">Temperature</span><span class="pl-kos">></span><span class="pl-kos">(</span><span class="pl-kos">)</span>
<span class="pl-kos">.</span><span class="pl-en">register</span><span class="pl-kos">::</span><span class="pl-kos"><</span><span class="pl-smi">Humidity</span><span class="pl-kos">></span><span class="pl-kos">(</span><span class="pl-kos">)</span>
<span class="pl-kos">.</span><span class="pl-en">register</span><span class="pl-kos">::</span><span class="pl-kos"><</span><span class="pl-smi">GpsLocation</span><span class="pl-kos">></span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<h3>Step 4: No other breaking API changes</h3>
<p>The 0.5.0 β 1.0.0 upgrade for <code>aimdb-core</code> has <strong>no breaking changes</strong> β only additive features (WebSocket URL scheme support). All existing code continues to compile unchanged.</p>
<h3>Step 5: Try the new tools</h3>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="# Update CLI
cargo install aimdb-cli
# Generate architecture diagrams from running instances
aimdb generate mermaid
# Watch live data
aimdb watch sensor.temperature"><pre><span class="pl-c"><span class="pl-c">#</span> Update CLI</span>
cargo install aimdb-cli
<span class="pl-c"><span class="pl-c">#</span> Generate architecture diagrams from running instances</span>
aimdb generate mermaid
<span class="pl-c"><span class="pl-c">#</span> Watch live data</span>
aimdb watch sensor.temperature</pre></div>
<hr>
<h2>π Examples</h2>
<p>All examples updated for v1.0.0:</p>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="git clone https://github.com/aimdb-dev/aimdb.git && cd aimdb
# MQTT connector demo
cargo run -p tokio-mqtt-connector-demo
# Weather mesh demo (multi-station with WebSocket streaming)
cargo run -p weather-hub
# Sync API demo
cargo run -p sync-api-demo
# Embedded (cross-compile)
cd examples/embassy-mqtt-connector-demo
cargo build --release --target thumbv7em-none-eabihf"><pre>git clone https://github.com/aimdb-dev/aimdb.git <span class="pl-k">&&</span> <span class="pl-c1">cd</span> aimdb
<span class="pl-c"><span class="pl-c">#</span> MQTT connector demo</span>
cargo run -p tokio-mqtt-connector-demo
<span class="pl-c"><span class="pl-c">#</span> Weather mesh demo (multi-station with WebSocket streaming)</span>
cargo run -p weather-hub
<span class="pl-c"><span class="pl-c">#</span> Sync API demo</span>
cargo run -p sync-api-demo
<span class="pl-c"><span class="pl-c">#</span> Embedded (cross-compile)</span>
<span class="pl-c1">cd</span> examples/embassy-mqtt-connector-demo
cargo build --release --target thumbv7em-none-eabihf</pre></div>
<hr>
<h2>π New Design Documents</h2>
<ul>
<li><strong>023 β Architecture Agent</strong>: LLM-powered session-based architecture design workflow</li>
<li><strong>024 β Codegen Common Crate</strong>: Architecture state to compilable Rust source</li>
<li><strong>025 β WASM Adapter</strong>: Full browser runtime design with React integration</li>
</ul>
<hr>
<h2>π€ Contributing</h2>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="git clone https://github.com/aimdb-dev/aimdb.git
cd aimdb
make check # fmt + clippy + test + embedded + wasm cross-compile"><pre>git clone https://github.com/aimdb-dev/aimdb.git
<span class="pl-c1">cd</span> aimdb
make check <span class="pl-c"><span class="pl-c">#</span> fmt + clippy + test + embedded + wasm cross-compile</span></pre></div>
<hr>
<h2>π License</h2>
<p>Apache License 2.0 β see <a href="https://github.com/aimdb-dev/aimdb/blob/main/LICENSE">LICENSE</a>.</p>
<hr>
github-actions[bot]
tag:github.com,2008:Repository/1061389408/v0.5.0
2026-02-22T18:45:08Z
v0.5.0 - Transforms, Persistence, Graph Introspection & Dynamic Routing
<h1>AimDB v0.5.0 Release Notes</h1>
<p><strong>Transforms, persistence, graph introspection, and dynamic routing!</strong></p>
<hr>
<h2>π― What's New in v0.5.0</h2>
<p>This release introduces <strong>reactive data transformations</strong>, a <strong>pluggable persistence layer</strong>, a <strong>dependency graph introspection API</strong>, and <strong>dynamic topic/address routing</strong> for connectors. It also ships two new crates (<code>aimdb-persistence</code>, <code>aimdb-persistence-sqlite</code>).</p>
<hr>
<h2>β¨ Major Features</h2>
<h3>π Transform API (Design 020)</h3>
<p><strong>Reactive data transformations between records β computed values that update automatically!</strong></p>
<div class="highlight highlight-source-rust notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="use aimdb_core::{AimDbBuilder, RecordKey};
// Single-input transform: derive Fahrenheit from Celsius
builder.configure::<Celsius>(AppKey::TempCelsius, |reg| {
reg.buffer(BufferCfg::SingleLatest);
});
builder.configure::<Fahrenheit>(AppKey::TempFahrenheit, |reg| {
reg.transform_raw(AppKey::TempCelsius, |c: Celsius| {
Fahrenheit { value: c.value * 9.0 / 5.0 + 32.0 }
});
});
// Multi-input join: combine humidity + temperature into comfort index
builder.configure::<ComfortIndex>(AppKey::Comfort, |reg| {
reg.transform_join_raw(|join| {
join.input::<Celsius>(AppKey::TempCelsius)
.input::<Humidity>(AppKey::Humidity)
.on_trigger(|trigger, state| {
// Called whenever any input changes
Some(ComfortIndex::compute(state))
})
});
});"><pre><span class="pl-k">use</span> aimdb_core<span class="pl-kos">::</span><span class="pl-kos">{</span><span class="pl-v">AimDbBuilder</span><span class="pl-kos">,</span> <span class="pl-v">RecordKey</span><span class="pl-kos">}</span><span class="pl-kos">;</span>
<span class="pl-c">// Single-input transform: derive Fahrenheit from Celsius</span>
builder<span class="pl-kos">.</span><span class="pl-en">configure</span><span class="pl-kos">::</span><span class="pl-kos"><</span><span class="pl-smi">Celsius</span><span class="pl-kos">></span><span class="pl-kos">(</span><span class="pl-smi">AppKey</span><span class="pl-kos">::</span><span class="pl-v">TempCelsius</span><span class="pl-kos">,</span> |reg| <span class="pl-kos">{</span>
reg<span class="pl-kos">.</span><span class="pl-en">buffer</span><span class="pl-kos">(</span><span class="pl-smi">BufferCfg</span><span class="pl-kos">::</span><span class="pl-v">SingleLatest</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
builder<span class="pl-kos">.</span><span class="pl-en">configure</span><span class="pl-kos">::</span><span class="pl-kos"><</span><span class="pl-smi">Fahrenheit</span><span class="pl-kos">></span><span class="pl-kos">(</span><span class="pl-smi">AppKey</span><span class="pl-kos">::</span><span class="pl-v">TempFahrenheit</span><span class="pl-kos">,</span> |reg| <span class="pl-kos">{</span>
reg<span class="pl-kos">.</span><span class="pl-en">transform_raw</span><span class="pl-kos">(</span><span class="pl-smi">AppKey</span><span class="pl-kos">::</span><span class="pl-v">TempCelsius</span><span class="pl-kos">,</span> |<span class="pl-s1">c</span><span class="pl-kos">:</span> <span class="pl-smi">Celsius</span>| <span class="pl-kos">{</span>
<span class="pl-smi">Fahrenheit</span> <span class="pl-kos">{</span> <span class="pl-c1">value</span><span class="pl-kos">:</span> c<span class="pl-kos">.</span><span class="pl-c1">value</span> <span class="pl-c1">*</span> <span class="pl-c1">9.0</span> / <span class="pl-c1">5.0</span> + <span class="pl-c1">32.0</span> <span class="pl-kos">}</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-c">// Multi-input join: combine humidity + temperature into comfort index</span>
builder<span class="pl-kos">.</span><span class="pl-en">configure</span><span class="pl-kos">::</span><span class="pl-kos"><</span><span class="pl-smi">ComfortIndex</span><span class="pl-kos">></span><span class="pl-kos">(</span><span class="pl-smi">AppKey</span><span class="pl-kos">::</span><span class="pl-v">Comfort</span><span class="pl-kos">,</span> |reg| <span class="pl-kos">{</span>
reg<span class="pl-kos">.</span><span class="pl-en">transform_join_raw</span><span class="pl-kos">(</span>|join| <span class="pl-kos">{</span>
join<span class="pl-kos">.</span><span class="pl-en">input</span><span class="pl-kos">::</span><span class="pl-kos"><</span><span class="pl-smi">Celsius</span><span class="pl-kos">></span><span class="pl-kos">(</span><span class="pl-smi">AppKey</span><span class="pl-kos">::</span><span class="pl-v">TempCelsius</span><span class="pl-kos">)</span>
<span class="pl-kos">.</span><span class="pl-en">input</span><span class="pl-kos">::</span><span class="pl-kos"><</span><span class="pl-smi">Humidity</span><span class="pl-kos">></span><span class="pl-kos">(</span><span class="pl-smi">AppKey</span><span class="pl-kos">::</span><span class="pl-v">Humidity</span><span class="pl-kos">)</span>
<span class="pl-kos">.</span><span class="pl-en">on_trigger</span><span class="pl-kos">(</span>|trigger<span class="pl-kos">,</span> state| <span class="pl-kos">{</span>
<span class="pl-c">// Called whenever any input changes</span>
<span class="pl-en">Some</span><span class="pl-kos">(</span><span class="pl-smi">ComfortIndex</span><span class="pl-kos">::</span><span class="pl-en">compute</span><span class="pl-kos">(</span>state<span class="pl-kos">)</span><span class="pl-kos">)</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<p><strong>Features:</strong></p>
<ul>
<li>π <strong>Single-input</strong> <code>transform_raw()</code> for simple derivations</li>
<li>π <strong>Multi-input</strong> <code>transform_join_raw()</code> with <code>JoinTrigger</code> event dispatch</li>
<li>π <strong>Mutual exclusion</strong>: a record cannot have both <code>.source()</code> and <code>.transform()</code></li>
<li>π <strong>Automatic spawning</strong>: transforms run as async tasks during <code>AimDb::build()</code></li>
<li>π <strong>Tracing integration</strong>: full lifecycle event logging</li>
</ul>
<h3>π Graph Introspection API (Design 021)</h3>
<p><strong>Visualize the dependency graph of your AimDB instance!</strong></p>
<div class="highlight highlight-source-rust notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="// Get full dependency graph
let nodes = db.graph_nodes();
let edges = db.graph_edges();
let order = db.graph_topo_order();
// Nodes show origin type and buffer config
for node in &nodes {
println!("{}: {:?} ({:?})", node.key, node.origin, node.buffer_info);
}
// Edges show data flow
for edge in &edges {
println!("{} β {} ({:?})", edge.from, edge.to, edge.edge_type);
}"><pre><span class="pl-c">// Get full dependency graph</span>
<span class="pl-k">let</span> nodes = db<span class="pl-kos">.</span><span class="pl-en">graph_nodes</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-k">let</span> edges = db<span class="pl-kos">.</span><span class="pl-en">graph_edges</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-k">let</span> order = db<span class="pl-kos">.</span><span class="pl-en">graph_topo_order</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-c">// Nodes show origin type and buffer config</span>
<span class="pl-k">for</span> node <span class="pl-k">in</span> <span class="pl-c1">&</span>nodes <span class="pl-kos">{</span>
<span class="pl-en">println</span><span class="pl-en">!</span><span class="pl-kos">(</span><span class="pl-s">"{}: {:?} ({:?})"</span><span class="pl-kos">,</span> node<span class="pl-kos">.</span>key<span class="pl-kos">,</span> node<span class="pl-kos">.</span>origin<span class="pl-kos">,</span> node<span class="pl-kos">.</span>buffer_info<span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>
<span class="pl-c">// Edges show data flow</span>
<span class="pl-k">for</span> edge <span class="pl-k">in</span> <span class="pl-c1">&</span>edges <span class="pl-kos">{</span>
<span class="pl-en">println</span><span class="pl-en">!</span><span class="pl-kos">(</span><span class="pl-s">"{} β {} ({:?})"</span><span class="pl-kos">,</span> edge<span class="pl-kos">.</span>from<span class="pl-kos">,</span> edge<span class="pl-kos">.</span>to<span class="pl-kos">,</span> edge<span class="pl-kos">.</span>edge_type<span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p><strong><code>RecordOrigin</code> variants:</strong></p>
<ul>
<li><code>Source</code> β direct producer writes</li>
<li><code>Link</code> β connector-bridged external data</li>
<li><code>Transform</code> β single-input reactive derivation</li>
<li><code>TransformJoin</code> β multi-input reactive join</li>
<li><code>Passive</code> β no producer (consumer-only)</li>
</ul>
<p><strong>Also available via <code>aimdb-client</code> and <code>aimdb-mcp</code> tools.</strong></p>
<h3>πΎ Persistence Layer (New Crates)</h3>
<p><strong>Long-term record history with pluggable backends!</strong></p>
<div class="highlight highlight-source-rust notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="use aimdb_persistence::AimDbBuilderPersistExt;
use aimdb_persistence_sqlite::SqliteBackend;
// Set up SQLite persistence with 7-day retention
let backend = SqliteBackend::new("./aimdb_history.db")?;
builder.with_persistence(backend, Duration::from_secs(7 * 24 * 3600));
// Mark records to persist
builder.configure::<Temperature>(AppKey::Temp, |reg| {
reg.buffer(BufferCfg::SingleLatest)
.persist("sensor.temperature"); // β stored to SQLite
});
let db = builder.build().await?;
// Query historical data
let last_100 = db.query_latest::<Temperature>("sensor.*", Some(100)).await;
let this_week = db.query_range::<Temperature>(
"sensor.*",
week_start_ms,
week_end_ms,
None, // no per-record limit
).await;"><pre><span class="pl-k">use</span> aimdb_persistence<span class="pl-kos">::</span><span class="pl-v">AimDbBuilderPersistExt</span><span class="pl-kos">;</span>
<span class="pl-k">use</span> aimdb_persistence_sqlite<span class="pl-kos">::</span><span class="pl-v">SqliteBackend</span><span class="pl-kos">;</span>
<span class="pl-c">// Set up SQLite persistence with 7-day retention</span>
<span class="pl-k">let</span> backend = <span class="pl-smi">SqliteBackend</span><span class="pl-kos">::</span><span class="pl-en">new</span><span class="pl-kos">(</span><span class="pl-s">"./aimdb_history.db"</span><span class="pl-kos">)</span>?<span class="pl-kos">;</span>
builder<span class="pl-kos">.</span><span class="pl-en">with_persistence</span><span class="pl-kos">(</span>backend<span class="pl-kos">,</span> <span class="pl-smi">Duration</span><span class="pl-kos">::</span><span class="pl-en">from_secs</span><span class="pl-kos">(</span><span class="pl-c1">7</span> <span class="pl-c1">*</span> <span class="pl-c1">24</span> <span class="pl-c1">*</span> <span class="pl-c1">3600</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-c">// Mark records to persist</span>
builder<span class="pl-kos">.</span><span class="pl-en">configure</span><span class="pl-kos">::</span><span class="pl-kos"><</span><span class="pl-smi">Temperature</span><span class="pl-kos">></span><span class="pl-kos">(</span><span class="pl-smi">AppKey</span><span class="pl-kos">::</span><span class="pl-v">Temp</span><span class="pl-kos">,</span> |reg| <span class="pl-kos">{</span>
reg<span class="pl-kos">.</span><span class="pl-en">buffer</span><span class="pl-kos">(</span><span class="pl-smi">BufferCfg</span><span class="pl-kos">::</span><span class="pl-v">SingleLatest</span><span class="pl-kos">)</span>
<span class="pl-kos">.</span><span class="pl-en">persist</span><span class="pl-kos">(</span><span class="pl-s">"sensor.temperature"</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// β stored to SQLite</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-k">let</span> db = builder<span class="pl-kos">.</span><span class="pl-en">build</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-k">await</span>?<span class="pl-kos">;</span>
<span class="pl-c">// Query historical data</span>
<span class="pl-k">let</span> last_100 = db<span class="pl-kos">.</span><span class="pl-en">query_latest</span><span class="pl-kos">::</span><span class="pl-kos"><</span><span class="pl-smi">Temperature</span><span class="pl-kos">></span><span class="pl-kos">(</span><span class="pl-s">"sensor.*"</span><span class="pl-kos">,</span> <span class="pl-en">Some</span><span class="pl-kos">(</span><span class="pl-c1">100</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-k">await</span><span class="pl-kos">;</span>
<span class="pl-k">let</span> this_week = db<span class="pl-kos">.</span><span class="pl-en">query_range</span><span class="pl-kos">::</span><span class="pl-kos"><</span><span class="pl-smi">Temperature</span><span class="pl-kos">></span><span class="pl-kos">(</span>
<span class="pl-s">"sensor.*"</span><span class="pl-kos">,</span>
week_start_ms<span class="pl-kos">,</span>
week_end_ms<span class="pl-kos">,</span>
<span class="pl-v">None</span><span class="pl-kos">,</span> <span class="pl-c">// no per-record limit</span>
<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-k">await</span><span class="pl-kos">;</span></pre></div>
<p><strong><code>aimdb-persistence</code> features:</strong></p>
<ul>
<li><code>PersistenceBackend</code> trait β implement your own storage</li>
<li>Automatic retention cleanup task (24-hour interval)</li>
<li><code>query_latest</code>, <code>query_range</code>, <code>query_raw</code> APIs</li>
</ul>
<p><strong><code>aimdb-persistence-sqlite</code> features:</strong></p>
<ul>
<li>WAL journal mode for concurrent reads</li>
<li>Window-function queries for efficient top-N per record</li>
<li><code>*</code> wildcard pattern matching</li>
<li>Actor-model writer thread; <code>Clone</code> = O(1) handle copy</li>
</ul>
<h3>π Dynamic Topic/Address Routing (Design 018)</h3>
<p><strong>Resolve MQTT topics or KNX group addresses at runtime based on data values!</strong></p>
<div class="highlight highlight-source-rust notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="// Outbound: per-message topic from payload
builder.configure::<SensorReading>(AppKey::Reading, |reg| {
reg.link_to("mqtt://broker/sensors/default")
.with_topic_provider(|reading: &SensorReading| {
format!("sensors/{}/data", reading.sensor_id)
});
});
// Inbound: late-binding topic from config/discovery
builder.configure::<Command>(AppKey::Command, |reg| {
reg.link_from("mqtt://broker/")
.with_topic_resolver(|| {
// Called once at connector startup
format!("commands/{}", load_device_id())
});
});"><pre><span class="pl-c">// Outbound: per-message topic from payload</span>
builder<span class="pl-kos">.</span><span class="pl-en">configure</span><span class="pl-kos">::</span><span class="pl-kos"><</span><span class="pl-smi">SensorReading</span><span class="pl-kos">></span><span class="pl-kos">(</span><span class="pl-smi">AppKey</span><span class="pl-kos">::</span><span class="pl-v">Reading</span><span class="pl-kos">,</span> |reg| <span class="pl-kos">{</span>
reg<span class="pl-kos">.</span><span class="pl-en">link_to</span><span class="pl-kos">(</span><span class="pl-s">"mqtt://broker/sensors/default"</span><span class="pl-kos">)</span>
<span class="pl-kos">.</span><span class="pl-en">with_topic_provider</span><span class="pl-kos">(</span>|<span class="pl-s1">reading</span><span class="pl-kos">:</span> <span class="pl-c1">&</span><span class="pl-smi">SensorReading</span>| <span class="pl-kos">{</span>
<span class="pl-en">format</span><span class="pl-en">!</span><span class="pl-kos">(</span><span class="pl-s">"sensors/{}/data"</span><span class="pl-kos">,</span> reading<span class="pl-kos">.</span>sensor_id<span class="pl-kos">)</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-c">// Inbound: late-binding topic from config/discovery</span>
builder<span class="pl-kos">.</span><span class="pl-en">configure</span><span class="pl-kos">::</span><span class="pl-kos"><</span><span class="pl-smi">Command</span><span class="pl-kos">></span><span class="pl-kos">(</span><span class="pl-smi">AppKey</span><span class="pl-kos">::</span><span class="pl-v">Command</span><span class="pl-kos">,</span> |reg| <span class="pl-kos">{</span>
reg<span class="pl-kos">.</span><span class="pl-en">link_from</span><span class="pl-kos">(</span><span class="pl-s">"mqtt://broker/"</span><span class="pl-kos">)</span>
<span class="pl-kos">.</span><span class="pl-en">with_topic_resolver</span><span class="pl-kos">(</span>|| <span class="pl-kos">{</span>
<span class="pl-c">// Called once at connector startup</span>
<span class="pl-en">format</span><span class="pl-en">!</span><span class="pl-kos">(</span><span class="pl-s">"commands/{}"</span><span class="pl-kos">,</span> load_device_id<span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<p><strong>Works in both <code>std</code> and <code>no_std + alloc</code> environments.</strong></p>
<h3>π‘ Record Drain API (Design 019)</h3>
<p><strong>Non-blocking batch pull for accumulated history β perfect for LLM analysis!</strong></p>
<div class="highlight highlight-source-rust notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="// Via AimDbClient (remote access)
let response = client.drain_record("sensor.temperature").await?;
println!("Drained {} values", response.count);
// First call is always empty (cold start β creates the reader)
// Subsequent calls return everything since last drain"><pre><span class="pl-c">// Via AimDbClient (remote access)</span>
<span class="pl-k">let</span> response = client<span class="pl-kos">.</span><span class="pl-en">drain_record</span><span class="pl-kos">(</span><span class="pl-s">"sensor.temperature"</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-k">await</span>?<span class="pl-kos">;</span>
<span class="pl-en">println</span><span class="pl-en">!</span><span class="pl-kos">(</span><span class="pl-s">"Drained {} values"</span><span class="pl-kos">,</span> response<span class="pl-kos">.</span>count<span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-c">// First call is always empty (cold start β creates the reader)</span>
<span class="pl-c">// Subsequent calls return everything since last drain</span></pre></div>
<p><strong>Cold-start semantics:</strong> the first drain call creates a reader and returns empty. Subsequent calls return all values accumulated since the previous drain. This enables stateful batch analysis without missing data.</p>
<hr>
<h2>π₯ Breaking Changes</h2>
<h3>1. <code>.with_serialization()</code> β <code>.with_remote_access()</code></h3>
<div class="highlight highlight-source-rust notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="// Before (v0.4.x)
reg.buffer(...).with_serialization();
// After (v0.5.0)
reg.buffer(...).with_remote_access();"><pre><span class="pl-c">// Before (v0.4.x)</span>
reg<span class="pl-kos">.</span><span class="pl-en">buffer</span><span class="pl-kos">(</span>..<span class="pl-kos">.</span><span class="pl-c1"></span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">with_serialization</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-c">// After (v0.5.0)</span>
reg<span class="pl-kos">.</span><span class="pl-en">buffer</span><span class="pl-kos">(</span>..<span class="pl-kos">.</span><span class="pl-c1"></span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">with_remote_access</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<h3>2. <code>RecordId::new()</code> requires <code>RecordOrigin</code></h3>
<p>This affects custom buffer/record implementations only:</p>
<div class="highlight highlight-source-rust notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="// Before (v0.4.x)
RecordId::new(type_id, idx)
// After (v0.5.0)
RecordId::new(type_id, idx, RecordOrigin::Source)"><pre><span class="pl-c">// Before (v0.4.x)</span>
<span class="pl-smi">RecordId</span><span class="pl-kos">::</span><span class="pl-en">new</span><span class="pl-kos">(</span>type_id<span class="pl-kos">,</span> idx<span class="pl-kos">)</span>
<span class="pl-c">// After (v0.5.0)</span><span class="pl-kos"></span>
<span class="pl-smi">RecordId</span><span class="pl-kos">::</span><span class="pl-en">new</span><span class="pl-kos">(</span>type_id<span class="pl-kos">,</span> idx<span class="pl-kos">,</span> <span class="pl-smi">RecordOrigin</span><span class="pl-kos">::</span><span class="pl-v">Source</span><span class="pl-kos">)</span><span class="pl-kos"></span></pre></div>
<h3>3. MCP subscription tools removed</h3>
<p>The <code>subscribe_record</code>, <code>unsubscribe_record</code>, <code>list_subscriptions</code>, and <code>get_notification_directory</code> MCP tools have been replaced by <code>drain_record</code>. Update any LLM prompts or MCP tool configurations accordingly.</p>
<hr>
<h2>π¦ Published Crates</h2>
<h3>New Crates</h3>
<ul>
<li>π <code>[email protected]</code> β pluggable persistence layer</li>
<li>π <code>[email protected]</code> β SQLite backend for persistence</li>
</ul>
<h3>Updated</h3>
<table>
<thead>
<tr>
<th>Crate</th>
<th>Version</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>aimdb-core</code></td>
<td><strong>0.5.0</strong></td>
</tr>
<tr>
<td><code>aimdb-tokio-adapter</code></td>
<td><strong>0.5.0</strong></td>
</tr>
<tr>
<td><code>aimdb-embassy-adapter</code></td>
<td><strong>0.5.0</strong></td>
</tr>
<tr>
<td><code>aimdb-client</code></td>
<td><strong>0.5.0</strong></td>
</tr>
<tr>
<td><code>aimdb-sync</code></td>
<td><strong>0.5.0</strong></td>
</tr>
<tr>
<td><code>aimdb-mqtt-connector</code></td>
<td><strong>0.5.0</strong></td>
</tr>
<tr>
<td><code>aimdb-knx-connector</code></td>
<td><strong>0.3.0</strong></td>
</tr>
<tr>
<td><code>aimdb-cli</code></td>
<td><strong>0.5.0</strong></td>
</tr>
<tr>
<td><code>aimdb-mcp</code></td>
<td><strong>0.5.0</strong></td>
</tr>
</tbody>
</table>
<h3>Unchanged</h3>
<ul>
<li><code>[email protected]</code></li>
<li><code>[email protected]</code></li>
</ul>
<hr>
<h2>π§ New MCP Tools</h2>
<p>The <code>aimdb-mcp</code> server now provides these tools:</p>
<table>
<thead>
<tr>
<th>Tool</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>discover_instances</code></td>
<td>Find running AimDB servers</td>
</tr>
<tr>
<td><code>list_records</code></td>
<td>List all records with metadata</td>
</tr>
<tr>
<td><code>get_record</code></td>
<td>Get current value</td>
</tr>
<tr>
<td><code>set_record</code></td>
<td>Set writable record value</td>
</tr>
<tr>
<td><code>query_schema</code></td>
<td>Infer JSON Schema from value</td>
</tr>
<tr>
<td><code>get_instance_info</code></td>
<td>Server version and capabilities</td>
</tr>
<tr>
<td><code>drain_record</code></td>
<td>Batch pull accumulated history</td>
</tr>
<tr>
<td><code>graph_nodes</code></td>
<td>All graph nodes with origin/buffer info</td>
</tr>
<tr>
<td><code>graph_edges</code></td>
<td>Directed data-flow edges</td>
</tr>
<tr>
<td><code>graph_topo_order</code></td>
<td>Topological record ordering</td>
</tr>
</tbody>
</table>
<hr>
<h2>π₯οΈ New CLI Commands (<code>aimdb graph</code>)</h2>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="# List all graph nodes (color-coded by origin)
aimdb graph nodes
# Show directed data-flow edges
aimdb graph edges
# Show topological (spawn) order
aimdb graph order
# Export to Graphviz DOT format
aimdb graph dot > pipeline.dot
dot -Tsvg pipeline.dot -o pipeline.svg"><pre><span class="pl-c"><span class="pl-c">#</span> List all graph nodes (color-coded by origin)</span>
aimdb graph nodes
<span class="pl-c"><span class="pl-c">#</span> Show directed data-flow edges</span>
aimdb graph edges
<span class="pl-c"><span class="pl-c">#</span> Show topological (spawn) order</span>
aimdb graph order
<span class="pl-c"><span class="pl-c">#</span> Export to Graphviz DOT format</span>
aimdb graph dot <span class="pl-k">></span> pipeline.dot
dot -Tsvg pipeline.dot -o pipeline.svg</pre></div>
<hr>
<h2>π Migration Guide</h2>
<h3>Step 1: Update dependencies</h3>
<div class="highlight highlight-source-toml notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="[dependencies]
aimdb-core = "0.5.0"
aimdb-tokio-adapter = "0.5.0"
# Optional: add persistence
aimdb-persistence = "0.1.0"
aimdb-persistence-sqlite = "0.1.0""><pre>[<span class="pl-en">dependencies</span>]
<span class="pl-smi">aimdb-core</span> = <span class="pl-s"><span class="pl-pds">"</span>0.5.0<span class="pl-pds">"</span></span>
<span class="pl-smi">aimdb-tokio-adapter</span> = <span class="pl-s"><span class="pl-pds">"</span>0.5.0<span class="pl-pds">"</span></span>
<span class="pl-c"><span class="pl-c">#</span> Optional: add persistence</span>
<span class="pl-smi">aimdb-persistence</span> = <span class="pl-s"><span class="pl-pds">"</span>0.1.0<span class="pl-pds">"</span></span>
<span class="pl-smi">aimdb-persistence-sqlite</span> = <span class="pl-s"><span class="pl-pds">"</span>0.1.0<span class="pl-pds">"</span></span></pre></div>
<h3>Step 2: Rename <code>.with_serialization()</code> β <code>.with_remote_access()</code></h3>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="# Quick find & replace
grep -rn "with_serialization" src/
# Replace with:
# .with_remote_access()"><pre><span class="pl-c"><span class="pl-c">#</span> Quick find & replace</span>
grep -rn <span class="pl-s"><span class="pl-pds">"</span>with_serialization<span class="pl-pds">"</span></span> src/
<span class="pl-c"><span class="pl-c">#</span> Replace with:</span>
<span class="pl-c"><span class="pl-c">#</span> .with_remote_access()</span></pre></div>
<h3>Step 3: Update <code>RecordId::new()</code> calls (custom buffer implementations only)</h3>
<div class="highlight highlight-source-rust notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="// Add RecordOrigin argument
RecordId::new(type_id, idx, RecordOrigin::Source)"><pre><span class="pl-c">// Add RecordOrigin argument</span>
<span class="pl-smi">RecordId</span><span class="pl-kos">::</span><span class="pl-en">new</span><span class="pl-kos">(</span>type_id<span class="pl-kos">,</span> idx<span class="pl-kos">,</span> <span class="pl-smi">RecordOrigin</span><span class="pl-kos">::</span><span class="pl-v">Source</span><span class="pl-kos">)</span><span class="pl-kos"></span></pre></div>
<h3>Step 4: Update MCP tool usage</h3>
<p>Replace <code>subscribe_record</code> / <code>unsubscribe_record</code> workflows with <code>drain_record</code> polling:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="# Old: subscribe β wait β unsubscribe
# New: call drain_record periodically (first call always empty)
drain_record(socket_path: "...", record_name: "sensor.*")"><pre class="notranslate"><code># Old: subscribe β wait β unsubscribe
# New: call drain_record periodically (first call always empty)
drain_record(socket_path: "...", record_name: "sensor.*")
</code></pre></div>
<hr>
<h2>π Examples</h2>
<p>All examples updated for v0.5.0:</p>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="git clone https://github.com/aimdb-dev/aimdb.git && cd aimdb
# MQTT connector demo
cargo run -p tokio-mqtt-connector-demo
# KNX connector demo
cargo run -p tokio-knx-connector-demo
# Sync API demo
cargo run -p sync-api-demo
# Weather mesh demo (multi-station)
cargo run -p weather-hub
# Embedded (cross-compile)
cd examples/embassy-mqtt-connector-demo
cargo build --release --target thumbv7em-none-eabihf"><pre>git clone https://github.com/aimdb-dev/aimdb.git <span class="pl-k">&&</span> <span class="pl-c1">cd</span> aimdb
<span class="pl-c"><span class="pl-c">#</span> MQTT connector demo</span>
cargo run -p tokio-mqtt-connector-demo
<span class="pl-c"><span class="pl-c">#</span> KNX connector demo</span>
cargo run -p tokio-knx-connector-demo
<span class="pl-c"><span class="pl-c">#</span> Sync API demo</span>
cargo run -p sync-api-demo
<span class="pl-c"><span class="pl-c">#</span> Weather mesh demo (multi-station)</span>
cargo run -p weather-hub
<span class="pl-c"><span class="pl-c">#</span> Embedded (cross-compile)</span>
<span class="pl-c1">cd</span> examples/embassy-mqtt-connector-demo
cargo build --release --target thumbv7em-none-eabihf</pre></div>
<hr>
<h2>π€ Contributing</h2>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="git clone https://github.com/aimdb-dev/aimdb.git
cd aimdb
make check # fmt + clippy + test + embedded cross-compile"><pre>git clone https://github.com/aimdb-dev/aimdb.git
<span class="pl-c1">cd</span> aimdb
make check <span class="pl-c"><span class="pl-c">#</span> fmt + clippy + test + embedded cross-compile</span></pre></div>
<hr>
<h2>π License</h2>
<p>Apache License 2.0 β see <a href="https://github.com/aimdb-dev/aimdb/blob/main/LICENSE">LICENSE</a>.</p>
<hr>
lxsaah
tag:github.com,2008:Repository/1061389408/aimdb-tokio-adapter-v0.5.0
2026-02-22T18:44:40Z
aimdb-tokio-adapter-v0.5.0
<p>aimdb-tokio-adapter v0.5.0</p>
lxsaah
tag:github.com,2008:Repository/1061389408/aimdb-sync-v0.5.0
2026-02-22T18:44:40Z
aimdb-sync-v0.5.0
<p>aimdb-sync v0.5.0</p>
lxsaah
tag:github.com,2008:Repository/1061389408/aimdb-persistence-v0.1.0
2026-02-22T18:44:40Z
aimdb-persistence-v0.1.0
<p>aimdb-persistence v0.1.0</p>
lxsaah
tag:github.com,2008:Repository/1061389408/aimdb-persistence-sqlite-v0.1.0
2026-02-22T18:44:40Z
aimdb-persistence-sqlite-v0.1.0
<p>aimdb-persistence-sqlite v0.1.0</p>
lxsaah
tag:github.com,2008:Repository/1061389408/aimdb-mqtt-connector-v0.5.0
2026-02-22T18:44:40Z
aimdb-mqtt-connector-v0.5.0
<p>aimdb-mqtt-connector v0.5.0</p>
lxsaah
tag:github.com,2008:Repository/1061389408/aimdb-mcp-v0.5.0
2026-02-22T18:44:40Z
aimdb-mcp-v0.5.0
<p>aimdb-mcp v0.5.0</p>
lxsaah
tag:github.com,2008:Repository/1061389408/aimdb-knx-connector-v0.3.0
2026-02-22T18:44:40Z
aimdb-knx-connector-v0.3.0
<p>aimdb-knx-connector v0.3.0</p>
lxsaah
tag:github.com,2008:Repository/1061389408/aimdb-embassy-adapter-v0.5.0
2026-02-22T18:44:40Z
aimdb-embassy-adapter-v0.5.0
<p>aimdb-embassy-adapter v0.5.0</p>
lxsaah