All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Note: This is the global changelog for the AimDB project. For detailed changes to individual crates, see their respective CHANGELOG.md files:
- aimdb-core/CHANGELOG.md
- aimdb-codegen/CHANGELOG.md
- aimdb-data-contracts/CHANGELOG.md
- aimdb-derive/CHANGELOG.md
- aimdb-executor/CHANGELOG.md
- aimdb-tokio-adapter/CHANGELOG.md
- aimdb-embassy-adapter/CHANGELOG.md
- aimdb-mqtt-connector/CHANGELOG.md
- aimdb-knx-connector/CHANGELOG.md
- aimdb-websocket-connector/CHANGELOG.md
- aimdb-ws-protocol/CHANGELOG.md
- aimdb-wasm-adapter/CHANGELOG.md
- aimdb-sync/CHANGELOG.md
- aimdb-client/CHANGELOG.md
- aimdb-persistence/CHANGELOG.md
- aimdb-persistence-sqlite/CHANGELOG.md
- tools/aimdb-cli/CHANGELOG.md
- tools/aimdb-mcp/CHANGELOG.md
- M16 — JSON codec extracted behind the
json-serializefeature;RecordValue::as_json()now works onno_std + alloc, not juststd(Design 032). Newaimdb-core::codecmodule:RemoteSerialize(blanket-impl'd for everyserdeSerialize + DeserializeOwnedtype), the object-safeJsonCodec<T>, and the zero-sizedSerdeJsonCodec.serde_jsonruns onalloc, so embedded targets can opt in;stdenables the feature transitively, so std builds are unaffected. (aimdb-core) - Embassy buffer + join-queue tests now run in CI (Issue #85). The join-queue tests previously sat behind
embassy-runtime, which pullsembassy-executor's cortex-m assembly and can't compile undercargo teston x86_64 — so ordering / backpressure / clone-routing regressions were never caught. Thejoin_queuemodule is now gated onembassy-sync, andmake testruns the embassy adapter's unit tests + doctests on the host (no executor). Also addsEmbassyBuffer::peek()and fixes a staleEmbassyBufferdoc example. (aimdb-embassy-adapter)
-
M15 —
latest_snapshotremoved; point-in-time reads go through the new buffer-nativeDynBuffer::peek()(Design 031).TypedRecord::latest()and AimXrecord.getread the buffer directly instead of a per-record snapshot mutex (one lock + clone off theproduce()hot path). Consequences: a.with_remote_access()record with no buffer now failsbuild()(was a silent runtime no-op);record.get/latest()on anSpmcRingrecord returnsnot_found/None(rings have no canonical latest — userecord.drain/record.subscribe);SingleLatestandMailboxare unaffected.TypedRecord::produceis removed — all writes go throughWriteHandle::push. Adapters implementpeek()per buffer type. (aimdb-core, aimdb-tokio-adapter, aimdb-embassy-adapter, aimdb-wasm-adapter) -
M16 —
with_remote_access()now requires thejson-serializefeature (transitively enabled bystd);with_read_only_serialization()removed (Design 032). The stored serializer/deserializer closures are replaced by a type-erasedArc<dyn JsonCodec<T>>. ASerialize-only record can no longer be exposed read-only over remote access. (aimdb-core) -
M13 —
Spawntrait removed across the workspace;AimDbBuilder::build()now returns(AimDb, AimDbRunner)(Issue #88, Design 028). Every future the database drives — producer services, taps, transforms, join forwarders, connector loops, the remote-access supervisor,on_starttasks — is collected at build time and driven by a singleFuturesUnorderedinsiderunner.run().await. Adapter implementations (TokioAdapter,EmbassyAdapter,WasmAdapter) drop theirimpl Spawn. Theembassy-task-pool-8/16/32features are deleted andEmbassyAdapter::new_with_networkno longer takes aSpawner. Connector authors must updateConnectorBuilder::build()to returnVec<BoxFuture>instead ofArc<dyn Connector>. See each crate's CHANGELOG for the per-crate impact.
1.1.0 - 2026-05-22
- Automatic stage profiling (Issue #58, RFC 014): New
profilingfeature onaimdb-coreautomatically measures wall-clock time per.source()/.tap()/.link()stage and exposescall_count/total/avg/min/maxcounters per stage. Name stages withRecordRegistrar::with_name("..."). Works onno_std + allocvia the runtime clock (aimdb_executor::TimeOps) andportable-atomicfor 64-bit atomics onthumbv7em. New MCP toolsget_stage_profiling(with bottleneck detection + recommendation) andreset_stage_profiling. Feature is off by default and zero-cost when disabled. (aimdb-core, aimdb-executor, aimdb-tokio-adapter, aimdb-embassy-adapter, aimdb-wasm-adapter, aimdb-client, tools/aimdb-mcp) remote-access-demoexercises stage profiling: TheTemperatureandSystemStatusrecords now run from in-AimDB.source()+.tap()tasks (with.with_name(...)stage labels) and the demo enables theprofilingfeature.SystemStatus.slow_status_processordeliberately sleeps 100 ms per value soget_stage_profilingflags it as the bottleneck. README documents how to query and reset profiling via MCP /socat.hello-mailboxexample (Issue #94): New minimal example demonstrating the Mailbox buffer (latest-wins) semantics using the synchronous API. First community contribution from @ggmaldo — see examples/hello-mailbox/.- Writer-exclusivity validation (Issue #89): Combining
.source(),.transform(), and.link_from()on the same record now panics at configuration time with a clear message instead of silently producing a last-writer-wins race on the buffer. Multiple.link_from()inbound connectors (fan-in) remain allowed. (aimdb-core) no_stdTransform API (Design 027):.transform()and.transform_join()are now available onno_std + alloctargets — no longer Tokio-only. Multi-input join fan-in moved out ofaimdb-coreinto the newJoinFanInRuntimetraits inaimdb-executor, with implementations in the Tokio (mpsc::channel, capacity 64), Embassy (embassy_sync::Channel, capacity 8), and WASM (futures_channel::mpsc, capacity 64) adapters. (aimdb-core, aimdb-executor, aimdb-tokio-adapter, aimdb-embassy-adapter, aimdb-wasm-adapter)- Task-model join handler: New
JoinBuilder::on_triggers(FnOnce(JoinEventRx, Producer) -> impl Future)API replaces the previous callback model. Eliminates per-event heap allocation and lets handler state borrow across.awaitpoints. Breaking change vs. the oldwith_state().on_trigger(...)form — see aimdb-core. - Weather-mesh
DewPointdemo: All three weather stations (alpha, beta, gamma) now derive aDewPointrecord fromTemperatureandHumidityviatransform_join, demonstrating the API end-to-end on Tokio and Embassy. - Design document: 027 (
no_stdSupport for Transform API) - MCP public mode: New
--publicflag restricts the MCP server to read-only tools for safe internet-facing deployments with SSRF protection (tools/aimdb-mcp) - MCP
--socketflag: Default socket path can be set at startup, simplifying single-instance workflows (tools/aimdb-mcp) - Context-Aware Deserializers (Design 026): Inbound connector deserializers can now receive a
RuntimeContext<R>for platform-independent timestamps and logging- New
.with_deserializer(|ctx, bytes| ...)API onInboundConnectorBuilderprovidesRuntimeContext<R>to deserialization closures - New
.with_deserializer_raw(|bytes| ...)for plain bytes-only deserialization when context is unnecessary DeserializerKindenum enforces mutual exclusivity between raw and context-aware deserializersRouter::route()propagates optional runtime context to context-aware routes
- New
- Context-Aware Serializers: Outbound connector serializers can now receive a
RuntimeContext<R>, symmetric with deserializers- New
.with_serializer(|ctx, value| ...)API onOutboundConnectorBuilderprovidesRuntimeContext<R>to serialization closures - New
.with_serializer_raw(|value| ...)for plain value-only serialization when context is unnecessary SerializerKindenum (Raw/Context) enforces mutual exclusivity- All outbound connector publishers updated to propagate runtime context via
db.runtime_any()
- New
- Design document: 026 (Context-Aware Deserializers)
- aimdb-executor:
TimeOpstrait gained a requiredduration_as_nanos(duration) -> u64method (runtime-agnostic numeric representation of elapsed time, used by stage profiling). Implemented in tokio, embassy, and wasm adapters. (aimdb-executor) - aimdb-embassy-adapter:
SpmcRingsubscriber-slot exhaustion now emits adefmt::error!with guidance to increase theCONSUMERSconst generic. Counting rule: one slot per.tap(),.link_to(), andtransform_joininput. - aimdb-codegen: Generated join handler stubs updated to the new
on_triggerstask model (async fn task_handler(JoinEventRx, Producer<...>)). - aimdb-core: Breaking API changes to
InboundConnectorLink,Router, andRouterBuilderto supportDeserializerKind(see aimdb-core/CHANGELOG.md) - aimdb-core: Breaking API change —
ConnectorLink.serializernow storesSerializerKindinstead ofSerializerFn - aimdb-core:
.with_serializer()renamed to.with_serializer_raw()for the old single-argument pattern - aimdb-mqtt-connector: Updated router dispatch for new
route()signature; outbound publishers dispatch viaSerializerKind - aimdb-knx-connector: Updated router dispatch for new
route()signature; outbound publishers dispatch viaSerializerKind - aimdb-websocket-connector: Updated router dispatch for new
route()signature; outbound publishers dispatch viaSerializerKind - All connector examples updated to use new
.with_deserializer(|_ctx, bytes| ...)and.with_serializer_raw(|value| ...)signatures rand0.8 → 0.10.1: Upgraded across workspace (aimdb-data-contracts,aimdb-embassy-adapter, examples). Migrated API:gen→random,SmallRngseed size 16 → 32, addedRngExtimports.- README: Reordered quickstart — remote MCP exploration (zero install) is now step 2, local Docker setup moved to step 3.
1.0.0 - 2026-03-16
- aimdb-core promoted to 1.0.0 — stable public API milestone
- aimdb-websocket-connector: New crate for real-time bidirectional WebSocket streaming
- Server mode (Axum-based) with
link_to("ws://topic")for pushing data to browser clients - Client mode (tokio-tungstenite) with
link_to("ws-client://host/topic")for AimDB-to-AimDB sync AuthHandlertrait for pluggable authentication- Client session management with automatic cleanup and late-join support
StreamableRegistryfor extensible type-erased dispatch — register types via.register::<T>()
- Server mode (Axum-based) with
- aimdb-ws-protocol: New crate with shared wire protocol types for the WebSocket ecosystem
ServerMessageandClientMessageenums with JSON-encoded"type"discriminant- MQTT-style wildcard topic matching (
#multi-level,*single-level)
- aimdb-wasm-adapter: New crate enabling AimDB to run in the browser via WebAssembly
- Full
aimdb-executortrait implementations (RuntimeAdapter,Spawn,TimeOps,Logger) Rc<RefCell<…>>buffers — zero-overhead for single-threaded WASMWasmDbfacade via#[wasm_bindgen]withconfigureRecord,get,set,subscribeWsBridge— WebSocket bridge connecting browser to remote AimDB serverSchemaRegistryfor type-erased record dispatch with extensible.register::<T>()API- React hooks:
useRecord<T>,useSetRecord<T>,useBridge
- Full
- aimdb-codegen: New crate for architecture-to-code generation
ArchitectureStatetype for reading.aimdb/state.tomldecision records- Mermaid diagram generation (
generate_mermaid) - Rust source generation (
generate_rust) — value structs, key enums,SchemaType/Linkableimpls,configure_schema()scaffolding - Common crate, hub crate, and binary crate scaffolding
- State validation module for architecture integrity checks
- aimdb-data-contracts: Refocused as a pure trait-definition crate (
SchemaType,Streamable,Linkable,Simulatable,Observable,Migratable)Streamabletrait as capability marker for types crossing serialization boundariesMigratabletrait withMigrationChainandMigrationStepfor schema evolution- Concrete contracts (Temperature, Humidity, GpsLocation) moved to application-level crates
- Removed closed
StreamableVisitordispatcher in favor of extensible registry pattern - Removed
tsfeature (ts-rsdependency)
- aimdb-core: Added
ws://andwss://URL scheme support inConnectorUrlfor WebSocket connectors - tools/aimdb-cli: New
aimdb generatesubcommand for Mermaid diagrams, Rust schema generation, and crate scaffolding viaaimdb-codegen - tools/aimdb-cli: New
aimdb watchsubcommand for live record monitoring - tools/aimdb-mcp: Architecture agent module with session state machine (
Idle → Gathering → Proposing → Resolve) - tools/aimdb-mcp: 16+ new MCP tools:
propose_add_record,propose_add_connector,propose_modify_buffer,propose_modify_fields,propose_modify_key_variants,remove_record,rename_record,reset_session,resolve_proposal,save_memory,validate_against_instance,get_architecture,get_buffer_metrics, and more - tools/aimdb-mcp: Architecture MCP resources — Mermaid diagram and validation results
- tools/aimdb-mcp:
CONVENTIONS.mdasset for architecture agent prompts - Design documents: 023 (Architecture Agent), 024 (Codegen Common Crate), 025 (WASM Adapter)
- aimdb-data-contracts: Restructured from schema+contract crate to pure trait-definition crate (version reset to 0.1.0)
- aimdb-websocket-connector: Replaced closed dispatcher with extensible
StreamableRegistry— users register types via builder.register::<T>() - aimdb-wasm-adapter:
SchemaRegistryupdated to use extensible.register::<T>()pattern - aimdb-knx-connector: Updated Embassy dependency versions (executor 0.10.0, time 0.5.1, sync 0.8.0, net 0.9.0)
- aimdb-mqtt-connector: Updated Embassy dependency versions (executor 0.10.0, time 0.5.1, sync 0.8.0, net 0.9.0)
- Embassy submodules updated to latest upstream commits
| Crate | Previous | New |
|---|---|---|
aimdb-core |
0.5.0 | 1.0.0 |
aimdb-data-contracts |
0.5.0 | 0.1.0 |
aimdb-cli |
0.5.0 | 0.6.0 |
aimdb-mcp |
0.5.0 | 0.6.0 |
aimdb-codegen |
— | 0.1.0 (new) |
aimdb-websocket-connector |
— | 0.1.0 (new) |
aimdb-ws-protocol |
— | 0.1.0 (new) |
aimdb-wasm-adapter |
— | 0.1.1 (new) |
aimdb-tokio-adapter |
0.5.0 | unchanged |
aimdb-embassy-adapter |
0.5.0 | unchanged |
aimdb-client |
0.5.0 | unchanged |
aimdb-sync |
0.5.0 | unchanged |
aimdb-mqtt-connector |
0.5.0 | 0.5.1 |
aimdb-knx-connector |
0.3.0 | 0.3.1 |
aimdb-persistence |
0.1.0 | unchanged |
aimdb-persistence-sqlite |
0.1.0 | unchanged |
aimdb-derive |
0.1.0 | unchanged |
aimdb-executor |
0.1.0 | unchanged |
0.5.0 - 2026-02-21
- aimdb-persistence: New crate providing a pluggable persistence layer for long-term record history
PersistenceBackendtrait withstore,query,cleanup, andinitializehooksAimDbBuilderPersistExttrait adding.with_persistence(backend, retention)toAimDbBuilder<R>RecordRegistrarPersistExttrait adding.persist(record_name)toRecordRegistrar<T, R>AimDbQueryExttrait withquery_latest,query_range, andquery_rawmethods- Automatic 24-hour retention cleanup task registration
- aimdb-persistence-sqlite: New crate providing a SQLite backend for
aimdb-persistenceSqliteBackendwith WAL journal mode, actor-model command dispatch, and window-function queries- Pattern-based queries with
*wildcard support and optional time/row-count limits - Dedicated OS writer thread;
Clone=O(1)handle copy
- aimdb-data-contracts: New crate for portable, versioned AimDB data schemas
- Optional features:
observable,simulatable,migratable,ts(TypeScript bindings viats-rs) - Schema versioning and migration support
- Optional features:
- Transform API (Design 020) in
aimdb-core: Reactive data transformations between recordstransform_raw()for single-input derivations andtransform_join_raw()for multi-input joinsTransformBuilderandJoinBuilderfluent APIs with optional stateful handlers- Transforms spawned as tasks during
AimDb::build(); mutual exclusion with.source()enforced
- Graph Introspection API (Design 021) in
aimdb-coreandaimdb-client:RecordOriginenum classifying record sources (Source,Link,Transform,TransformJoin,Passive)GraphNode,GraphEdge,DependencyGraphtypes for full graph representationgraph_nodes(),graph_edges(),graph_topo_order()methods onAimDbandAimDbClient
- Record Drain API (Design 019) in
aimdb-core,aimdb-tokio-adapter, andaimdb-client:try_recv()onBufferReaderfor non-blocking batch pullsrecord.drainAimX protocol method with cold-start semantics and optional limitDrainResponsetype inaimdb-client
- Dynamic Topic/Address Routing (Design 018) in
aimdb-core,aimdb-mqtt-connector,aimdb-knx-connector:TopicProvider<T>trait for per-message outbound topic/address determinationTopicResolverFnfor late-binding inbound topic resolution at connector startupwith_topic_provider()andwith_topic_resolver()builder methods on connector links
- Graph Tools in
tools/aimdb-mcp:graph_nodes,graph_edges,graph_topo_orderMCP tools for LLM-powered graph explorationdrain_recordMCP tool for batch history access with persistent cold-start reader
- Graph Commands in
tools/aimdb-cli:aimdb graph nodes,graph edges,graph order,graph dotsubcommands- Color-coded output and DOT format export for Graphviz visualization
- Extension Macro in
aimdb-core:impl_record_registrar_ext!for generating runtime adapter extension traits
- aimdb-core: Renamed
.with_serialization()to.with_remote_access()for clearer semantics (breaking) - aimdb-core:
RecordId::new()now requires aRecordOriginparameter for dependency graph support (breaking) - aimdb-core:
set_from_jsonnow also rejects writes on records with active transforms - aimdb-core:
collect_outbound_routes()returnsOutboundRoutetuples with optionalTopicProviderFn - aimdb-core:
collect_inbound_routes()callslink.resolve_topic()for dynamic topic resolution - tools/aimdb-mcp: Replaced real-time subscription system with simpler drain-based polling
- Removed
subscribe_record,unsubscribe_record,list_subscriptions,get_notification_directorytools - Simplified architecture reduces infrastructure complexity for LLM clients
- Removed
| Crate | Previous | New |
|---|---|---|
aimdb-core |
0.4.0 | 0.5.0 |
aimdb-tokio-adapter |
0.4.0 | 0.5.0 |
aimdb-embassy-adapter |
0.4.0 | 0.5.0 |
aimdb-client |
0.4.0 | 0.5.0 |
aimdb-sync |
0.4.0 | 0.5.0 |
aimdb-mqtt-connector |
0.4.0 | 0.5.0 |
aimdb-knx-connector |
0.2.0 | 0.3.0 |
aimdb-cli |
0.4.0 | 0.5.0 |
aimdb-mcp |
0.4.0 | 0.5.0 |
aimdb-persistence |
— | 0.1.0 (new) |
aimdb-persistence-sqlite |
— | 0.1.0 (new) |
aimdb-derive |
0.1.0 | unchanged |
aimdb-executor |
0.1.0 | unchanged |
0.4.0 - 2025-12-25
- aimdb-derive: New crate providing
#[derive(RecordKey)]macro for compile-time checked record keys#[key = "..."]attribute for string representation#[key_prefix = "..."]attribute for namespace prefixing#[link_address = "..."]attribute for connector metadata (MQTT topics, KNX addresses)- Auto-generates
Hashimplementation to satisfyBorrow<str>contract
- aimdb-core:
RecordKeyis now a trait instead of a struct, enabling user-defined enum keysRecordKeytrait withas_str()and optionallink_address()methodsStringKeytype replaces oldRecordKeystruct (static/interned string keys)derivefeature flag to enable#[derive(RecordKey)]macro- Blanket implementation for
&'static str
- examples: New
mqtt-connector-demo-commonandknx-connector-demo-commoncrates for shared cross-platform types and monitors - docs: Added design documents:
016-M6-record-key-trait.md- RecordKey trait design017-M6-record-key-hash-impl.md- Hash implementation for Borrow compliance
- aimdb-mqtt-connector: Fixed initialization deadlock when subscribing to >10 MQTT topics (Issue #63)
- Event loop now spawned before subscribing (spawn-before-subscribe pattern)
- Dynamic channel capacity scales with topic count (
topics + 10)
- aimdb-mqtt-connector: Upgraded
rumqttcdependency from 0.24 to 0.25 - deny.toml: Added
OpenSSLlicense allowance (transitive via rumqttc/rustls) - deny.toml: Ignored
RUSTSEC-2025-0134advisory (rustls-pemfile unmaintained but not vulnerable)
0.3.0 - 2025-12-15
- aimdb-core: New
RecordIdtype for stable O(1) record indexing (Issue #60) - aimdb-core: New
RecordKeytype for string-based record identification with zero-alloc static keys - aimdb-core: Key-based producer/consumer API:
produce_by_key(),subscribe_by_key(),producer_by_key(),consumer_by_key() - aimdb-core:
ProducerByKey<T, R>andConsumerByKey<T, R>types for key-bound access - aimdb-core:
records_of_type::<T>()introspection method to find all records of a given type - aimdb-core:
resolve_key()method for O(1) key-to-RecordId lookups - aimdb-core: New error variants:
RecordKeyNotFound,InvalidRecordId,TypeMismatch,AmbiguousType,DuplicateRecordKey - aimdb-core:
RecordMetadatanow includesrecord_idandrecord_keyfields - aimdb-tokio-adapter: Multi-instance tests validating same-type different-key scenarios
- aimdb-core: New
BufferMetricstrait andBufferMetricsSnapshotstruct for buffer introspection (feature-gated behindmetrics)produced_count: Total items pushed to the bufferconsumed_count: Total items consumed across all readersdropped_count: Total items dropped due to lag (with per-reader semantics documented)occupancy: Current buffer fill level as(current, capacity)tuple
- aimdb-core:
RecordMetadatanow includes optional buffer metrics fields whenmetricsfeature is enabled - aimdb-tokio-adapter: Full
BufferMetricsimplementation for all buffer types (SPMC Ring, SingleLatest, Mailbox) - aimdb-tokio-adapter: Comprehensive test suite for metrics (
metrics_testsmodule) - Makefile: Added test targets for
metricsfeature combinations - docs: Added design document
015-M6-record-id-architecture.mdfor future RecordId-based storage
- aimdb-core:
configure<T>()now requires a key parameter:configure::<T>("key", |reg| ...) - aimdb-core: Internal storage changed from
BTreeMap<TypeId>toVec+HashMapindexes for O(1) hot-path access - aimdb-core:
SecurityPolicy::ReadWritenow usesHashSet<String>for writable record keys - aimdb-core: Added
hashbrowndependency for no_std-compatible HashMap - deny.toml: Added
Zliblicense allowance (used byfoldhash, hashbrown's default hasher) - aimdb-core:
DynBuffertrait no longer has a blanket implementation. Each adapter now provides its own explicit implementation. This enables adapters to providemetrics_snapshot()when themetricsfeature is enabled.
Breaking: configure<T>() now requires a key parameter
The record registration API now requires an explicit key for each record:
// Before (v0.2.x)
builder.configure::<Temperature>(|reg| {
reg.buffer(BufferCfg::SingleLatest);
});
// After (v0.3.0)
builder.configure::<Temperature>("sensor.temperature", |reg| {
reg.buffer(BufferCfg::SingleLatest);
});Key naming conventions:
- Use dot-separated hierarchical names:
"sensors.indoor","config.app" - Keys must be unique across all records (duplicate keys panic at registration)
- For single-instance records, any descriptive string works (e.g.,
"sensor.temperature","app.config")
Breaking: Type-based lookup may return AmbiguousType error
If you register multiple records of the same type, type-based methods (produce(), subscribe(), producer(), consumer()) will return AmbiguousType error:
// With multiple Temperature records registered...
db.produce(temp).await // Returns Err(AmbiguousType { count: 2, ... })
// Use key-based methods instead:
db.produce_by_key("sensors.indoor", temp).await // Works correctlyNew key-based API (recommended for multi-instance scenarios):
// Key-bound producer/consumer
let indoor_producer = db.producer_by_key::<Temperature>("sensors.indoor");
let outdoor_producer = db.producer_by_key::<Temperature>("sensors.outdoor");
// Each produces to its own record
indoor_producer.produce(temp).await?;
outdoor_producer.produce(temp).await?;
// Introspection
let temp_ids = db.records_of_type::<Temperature>(); // Returns &[RecordId]
let id = db.resolve_key("sensors.indoor"); // Returns Option<RecordId>Breaking: DynBuffer no longer has blanket impl
If you have custom Buffer<T> implementations, you now need to also implement DynBuffer<T>:
// Before (v0.2.x) - automatic via blanket impl
impl<T: Clone + Send> Buffer<T> for MyBuffer<T> { ... }
// DynBuffer was automatically implemented
// After (v0.3.0) - explicit implementation required
impl<T: Clone + Send> Buffer<T> for MyBuffer<T> { ... }
impl<T: Clone + Send + 'static> DynBuffer<T> for MyBuffer<T> {
fn push(&self, value: T) {
<Self as Buffer<T>>::push(self, value)
}
fn subscribe_boxed(&self) -> Box<dyn BufferReader<T> + Send> {
Box::new(self.subscribe())
}
fn as_any(&self) -> &dyn core::any::Any {
self
}
// Optional: implement metrics_snapshot() if you support metrics
#[cfg(feature = "metrics")]
fn metrics_snapshot(&self) -> Option<BufferMetricsSnapshot> {
None // or Some(...) if you track metrics
}
}0.2.0 - 2025-11-20
This release introduces bidirectional connector support, enabling true two-way data synchronization between AimDB and external systems. The new architecture supports simultaneous publishing and subscribing with automatic message routing, working seamlessly across both Tokio (std) and Embassy (no_std) runtimes.
- 🔄 Bidirectional Connectors: New
.link_to()and.link_from()APIs for clear directional data flows - 🎯 Type-Erased Router: Automatic routing of incoming messages to correct typed producers
- 🏗️ ConnectorBuilder Pattern: Simplified connector registration with automatic initialization
- 📡 Enhanced MQTT Connector: Complete rewrite supporting simultaneous pub/sub with automatic reconnection
- 🌐 Embassy Network Integration: Connectors can now access Embassy's network stack for network operations
- 📚 Comprehensive Guide: New 1000+ line connector development guide with real-world examples
- aimdb-core:
.build()is now async; connector registration changed from.with_connector(scheme, instance)to.with_connector(builder) - aimdb-core:
.link()deprecated in favor of.link_to()(outbound) and.link_from()(inbound) - aimdb-core: Outbound connector architecture refactored to trait-based system:
- Removed:
TypedRecord::spawn_outbound_consumers()method (was called automatically) - Added:
ConsumerTrait,AnyReadertraits for type-erased outbound routing - Added:
AimDb::collect_outbound_routes()method to gather configured routes - Required: Connectors must implement
spawn_outbound_publishers()and call it inConnectorBuilder::build()
- Removed:
- aimdb-mqtt-connector: API changed from
MqttConnector::new()toMqttConnectorBuilder::new(); automatic task spawning removes need for manual background task management - aimdb-mqtt-connector: Added
spawn_outbound_publishers()method; must be called inbuild()for outbound publishing to work
See individual changelogs for detailed changes:
- aimdb-core: Core connector architecture, router system, bidirectional APIs
- aimdb-tokio-adapter: Connector builder integration
- aimdb-embassy-adapter: Network stack access, connector support
- aimdb-mqtt-connector: Complete bidirectional rewrite for both runtimes
- aimdb-sync: Compatibility with async build
1. Update connector registration:
// Old (v0.1.0)
let mqtt = MqttConnector::new("mqtt://broker:1883").await?;
builder.with_connector("mqtt", Arc::new(mqtt))
// New (v0.2.0)
builder.with_connector(MqttConnectorBuilder::new("mqtt://broker:1883"))2. Make build() async:
// Old (v0.1.0)
let db = builder.build()?;
// New (v0.2.0)
let db = builder.build().await?;3. Use directional link methods:
// Old (v0.1.0)
.link("mqtt://sensors/temp")
// New (v0.2.0)
.link_to("mqtt://sensors/temp") // For publishing (AimDB → External)
.link_from("mqtt://commands/temp") // For subscribing (External → AimDB)4. Remove manual MQTT task spawning (Embassy):
// Old (v0.1.0) - Manual task spawning required
let mqtt_result = MqttConnector::create(...).await?;
spawner.spawn(mqtt_task(mqtt_result.task))?;
builder.with_connector("mqtt", Arc::new(mqtt_result.connector))
// New (v0.2.0) - Automatic task spawning
builder.with_connector(MqttConnectorBuilder::new("mqtt://broker:1883"))
// Tasks spawn automatically during build()5. Update custom connectors to spawn outbound publishers:
If you've implemented a custom connector, you must add spawn_outbound_publishers() support:
// Old (v0.1.0) - Outbound consumers spawned automatically
impl ConnectorBuilder for MyConnectorBuilder {
fn build<R>(&self, db: &AimDb<R>) -> DbResult<Arc<dyn Connector>> {
// ... setup code ...
Ok(Arc::new(MyConnector { /* fields */ }))
}
// Outbound publishing happened automatically via TypedRecord::spawn_outbound_consumers()
}
// New (v0.2.0) - Must explicitly spawn outbound publishers
impl ConnectorBuilder for MyConnectorBuilder {
fn build<R>(&self, db: &AimDb<R>) -> DbResult<Arc<dyn Connector>> {
// ... setup code ...
let connector = MyConnector { /* fields */ };
// REQUIRED: Collect and spawn outbound publishers
let outbound_routes = db.collect_outbound_routes(self.protocol_name());
connector.spawn_outbound_publishers(db, outbound_routes)?;
Ok(Arc::new(connector))
}
}
// REQUIRED: Implement spawn_outbound_publishers method
impl MyConnector {
fn spawn_outbound_publishers<R: RuntimeAdapter + 'static>(
&self,
db: &AimDb<R>,
routes: Vec<(String, Box<dyn ConsumerTrait>, SerializerFn, Vec<(String, String)>)>,
) -> DbResult<()> {
for (topic, consumer, serializer, _config) in routes {
let client = self.client.clone();
let topic_clone = topic.clone();
db.runtime().spawn(async move {
// Subscribe to record updates using ConsumerTrait
match consumer.subscribe_any().await {
Ok(mut reader) => {
loop {
match reader.recv_any().await {
Ok(value) => {
// Serialize and publish
if let Ok(bytes) = serializer(&*value) {
let _ = client.publish(&topic_clone, bytes).await;
}
}
Err(_) => break,
}
}
}
Err(_) => { /* Log error */ }
}
})?;
}
Ok(())
}
}Why this change? The new trait-based architecture provides:
- ✅ Symmetry with inbound routing (
ProducerTrait↔ConsumerTrait) - ✅ Testability (can mock
ConsumerTraitwithout real records) - ✅ Type safety via factory pattern (type capture at configuration time)
- ✅ Maintainability (connector logic stays in connector crate)
Migration checklist for custom connectors:
- Add
spawn_outbound_publishers()method to connector implementation - Call
db.collect_outbound_routes(protocol_name)inConnectorBuilder::build() - Call
connector.spawn_outbound_publishers(db, routes)?before returning - Use
ConsumerTrait::subscribe_any()to get type-erased readers - Handle serialization with provided
SerializerFn - Test both inbound (
.link_from()) and outbound (.link_to()) data flows
See Connector Development Guide for complete examples.
- Added comprehensive Connector Development Guide
- Updated MQTT connector examples for both Tokio and Embassy
- Enhanced API documentation with bidirectional patterns
0.1.0 - 2025-11-06
- Initial release of AimDB async in-memory database engine
- Type-safe record system using
TypeId-based routing - Three buffer types for different data flow patterns:
- SPMC Ring Buffer: High-frequency data streams with bounded memory
- SingleLatest: State synchronization and configuration updates
- Mailbox: Commands and one-shot events
- Producer-consumer model with async task spawning
- Runtime adapter abstraction for cross-platform support
no_stdcompatibility for embedded targets- Error handling with comprehensive
DbResult<T>andDbErrortypes - Remote access protocol (AimX v1) for cross-process introspection
- Tokio Adapter (
aimdb-tokio-adapter): Full-featured std runtime support- Lock-free buffer implementations
- Configurable buffer capacities
- Comprehensive async task spawning
- Embassy Adapter (
aimdb-embassy-adapter): Embeddedno_stdruntime support- Configurable task pool sizes (8/16/32 concurrent tasks)
- Optimized for resource-constrained devices
- Compatible with ARM Cortex-M targets
- Dual runtime support for both Tokio and Embassy
- Automatic consumer registration via builder pattern
- Topic mapping with QoS and retain configuration
- Pluggable serializers (JSON, MessagePack, Postcard, custom)
- Automatic reconnection handling
- Uses
rumqttcfor std environments - Uses
mountain-mqttfor embedded environments
- MCP Server (
aimdb-mcp): LLM-powered introspection and debugging- Discover running AimDB instances
- Query record values and schemas
- Subscribe to live updates
- Set writable record values
- JSON Schema inference from record values
- Notification persistence to JSONL files
- CLI Tool (
aimdb-cli): Command-line interface (skeleton)- Instance discovery and management commands
- Record inspection capabilities
- Live watch functionality
- Client Library (
aimdb-client): Reusable connection and discovery logic- Unix domain socket communication
- AimX v1 protocol implementation
- Clean error handling
- Blocking wrapper around async AimDB core
- Thread-safe synchronous record access
- Automatic Tokio runtime management
- Ideal for gradual migration from sync to async
- Comprehensive README with architecture overview
- Individual crate documentation with examples
- 12 detailed design documents in
/docs/design - Working examples:
tokio-mqtt-connector-demo: Full Tokio MQTT integrationembassy-mqtt-connector-demo: Embedded RP2040 with WiFi MQTTsync-api-demo: Synchronous API usage patternsremote-access-demo: Cross-process introspection server
- Comprehensive Makefile with color-coded output
- GitHub Actions workflows:
- Continuous integration (format, lint, test)
- Security audits (weekly schedule + on-demand)
- Documentation generation
- Release automation
- Cross-compilation testing for
thumbv7em-none-eabihftarget cargo-denyconfiguration for license and dependency auditing- Dev container setup for consistent development environment
- ✅ Sub-50ms latency for data synchronization
- ✅ Lock-free buffer operations
- ✅ Cross-platform support (MCU → edge → cloud)
- ✅ Type safety with zero-cost abstractions
- ✅ Protocol-agnostic connector architecture
- Kafka and DDS connectors planned for future releases
- CLI tool is currently skeleton implementation
- Performance benchmarks not yet included
- Limited to Unix domain sockets for remote access (no TCP yet)
- Rust 1.75+ required
- Tokio 1.47+ for std environments
- Embassy 0.9+ for embedded environments
- See
deny.tomlfor approved dependency licenses
None (initial release)
Not applicable (initial release)
AimDB v0.1.0 establishes the foundational architecture for async, in-memory data synchronization across MCU → edge → cloud environments. This release focuses on core functionality, dual runtime support, and developer tooling.
Highlights:
- 🚀 Dual runtime support: Works on both standard library (Tokio) and embedded (Embassy)
- 🔒 Type-safe record system eliminates runtime string lookups
- 📦 Three buffer types cover most data patterns
- 🔌 MQTT connector works in both std and
no_stdenvironments - 🤖 MCP server enables LLM-powered introspection
- ✅ 27+ core tests, comprehensive CI/CD, security auditing
Get Started:
cargo add aimdb-core aimdb-tokio-adapterSee README.md for quickstart guide and examples.
Feedback Welcome: This is an early release. Please report issues, suggest features, or contribute at: https://github.com/aimdb-dev/aimdb