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::&lt;T&gt;()</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(&quot;0.0.0.0:8080&quot;) .path(&quot;/ws&quot;) .with_late_join(true), ); // Push records to browser clients builder.configure::&lt;Temperature&gt;(AppKey::Temp, |reg| { reg.buffer(BufferCfg::SingleLatest) .link_to(&quot;ws://temperature&quot;); // ← 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">&lt;</span><span class="pl-smi">Temperature</span><span class="pl-kos">&gt;</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::&lt;T&gt;()</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(&quot;ws://localhost:8080/ws&quot;); const temp = useRecord&lt;Temperature&gt;(bridge, &quot;sensor.temperature&quot;); return &lt;div&gt;Current: {temp?.celsius}Β°C&lt;/div&gt;; }"><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">&lt;</span><span class="pl-smi">Temperature</span><span class="pl-c1">&gt;</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">&lt;</span><span class="pl-s1">div</span><span class="pl-c1">&gt;</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">&lt;/</span><span class="pl-s1">div</span><span class="pl-c1">&gt;</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&lt;RefCell&lt;…&gt;&gt;</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&lt;T&gt;</code>, <code>useSetRecord&lt;T&gt;</code>, <code>useBridge</code></li> <li>πŸ“‹ <code>SchemaRegistry</code> for type-erased record dispatch with extensible <code>.register::&lt;T&gt;()</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::&lt;T&gt;()</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 &lt;record&gt; # 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">&lt;</span>record<span class="pl-k">&gt;</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 = &quot;1.0&quot; aimdb-data-contracts = &quot;0.1&quot; # reset β€” now a pure trait crate aimdb-tokio-adapter = &quot;0.5&quot; # unchanged # Optional: add WebSocket streaming aimdb-websocket-connector = &quot;0.1&quot; # Optional: add WASM support aimdb-wasm-adapter = &quot;0.1&quot;"><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::&lt;T&gt;()</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::&lt;Temperature&gt;() .register::&lt;Humidity&gt;() .register::&lt;GpsLocation&gt;();"><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">&lt;</span><span class="pl-smi">Temperature</span><span class="pl-kos">&gt;</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">&lt;</span><span class="pl-smi">Humidity</span><span class="pl-kos">&gt;</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">&lt;</span><span class="pl-smi">GpsLocation</span><span class="pl-kos">&gt;</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 &amp;&amp; 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">&amp;&amp;</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::&lt;Celsius&gt;(AppKey::TempCelsius, |reg| { reg.buffer(BufferCfg::SingleLatest); }); builder.configure::&lt;Fahrenheit&gt;(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::&lt;ComfortIndex&gt;(AppKey::Comfort, |reg| { reg.transform_join_raw(|join| { join.input::&lt;Celsius&gt;(AppKey::TempCelsius) .input::&lt;Humidity&gt;(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">&lt;</span><span class="pl-smi">Celsius</span><span class="pl-kos">&gt;</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">&lt;</span><span class="pl-smi">Fahrenheit</span><span class="pl-kos">&gt;</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">&lt;</span><span class="pl-smi">ComfortIndex</span><span class="pl-kos">&gt;</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">&lt;</span><span class="pl-smi">Celsius</span><span class="pl-kos">&gt;</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">&lt;</span><span class="pl-smi">Humidity</span><span class="pl-kos">&gt;</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 &amp;nodes { println!(&quot;{}: {:?} ({:?})&quot;, node.key, node.origin, node.buffer_info); } // Edges show data flow for edge in &amp;edges { println!(&quot;{} β†’ {} ({:?})&quot;, 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">&amp;</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">&amp;</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(&quot;./aimdb_history.db&quot;)?; builder.with_persistence(backend, Duration::from_secs(7 * 24 * 3600)); // Mark records to persist builder.configure::&lt;Temperature&gt;(AppKey::Temp, |reg| { reg.buffer(BufferCfg::SingleLatest) .persist(&quot;sensor.temperature&quot;); // ← stored to SQLite }); let db = builder.build().await?; // Query historical data let last_100 = db.query_latest::&lt;Temperature&gt;(&quot;sensor.*&quot;, Some(100)).await; let this_week = db.query_range::&lt;Temperature&gt;( &quot;sensor.*&quot;, 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">&lt;</span><span class="pl-smi">Temperature</span><span class="pl-kos">&gt;</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">&lt;</span><span class="pl-smi">Temperature</span><span class="pl-kos">&gt;</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">&lt;</span><span class="pl-smi">Temperature</span><span class="pl-kos">&gt;</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::&lt;SensorReading&gt;(AppKey::Reading, |reg| { reg.link_to(&quot;mqtt://broker/sensors/default&quot;) .with_topic_provider(|reading: &amp;SensorReading| { format!(&quot;sensors/{}/data&quot;, reading.sensor_id) }); }); // Inbound: late-binding topic from config/discovery builder.configure::&lt;Command&gt;(AppKey::Command, |reg| { reg.link_from(&quot;mqtt://broker/&quot;) .with_topic_resolver(|| { // Called once at connector startup format!(&quot;commands/{}&quot;, 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">&lt;</span><span class="pl-smi">SensorReading</span><span class="pl-kos">&gt;</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">&amp;</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">&lt;</span><span class="pl-smi">Command</span><span class="pl-kos">&gt;</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(&quot;sensor.temperature&quot;).await?; println!(&quot;Drained {} values&quot;, 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 &gt; 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">&gt;</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 = &quot;0.5.0&quot; aimdb-tokio-adapter = &quot;0.5.0&quot; # Optional: add persistence aimdb-persistence = &quot;0.1.0&quot; aimdb-persistence-sqlite = &quot;0.1.0&quot;"><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 &amp; replace grep -rn &quot;with_serialization&quot; src/ # Replace with: # .with_remote_access()"><pre><span class="pl-c"><span class="pl-c">#</span> Quick find &amp; 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: &quot;...&quot;, record_name: &quot;sensor.*&quot;)"><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 &amp;&amp; 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">&amp;&amp;</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