How DimOS In[T] and Out[T] Streams Enable Inter-Module Communication
DimOS In[T] and Out[T] streams provide type-safe, zero-boilerplate inter-module communication by using Python type hints to automatically wire publisher-subscriber relationships, abstracting the underlying transport mechanism for both in-process and distributed execution.
The dimensionalOS/dimos repository implements a declarative streaming architecture where modules communicate through generic In[T] and Out[T] type annotations. This design eliminates manual message bus configuration while maintaining strict type safety across process boundaries.
Type-Safe Stream Declaration
Every DimOS subsystem inherits from the Module base class and declares its communication interface using generic type hints. When a module is instantiated, Module.__init__ inspects these annotations to construct the appropriate stream objects.
In dimos/core/module.py (lines 22-30), the initialization loop iterates over the class annotations. For each Out[T] declaration, the system creates a publish-only stream object; for each In[T] declaration, it creates a subscriber-only stream. This happens automatically during construction, requiring no explicit stream initialization code from developers.
Core Stream Objects
The streaming layer defines distinct objects for publishing and subscribing, each optimized for their specific role.
Out[T]: The Publisher Interface
Defined at line 139 of dimos/core/stream.py, the Out[T] class maintains a list of local callbacks and holds a reference to a transport object. When publish() is called, the Out[T] instance invokes Transport.broadcast to distribute the message to all connected subscribers, whether they reside in the same process or on remote machines.
In[T]: The Subscriber Interface
The In[T] class, defined at line 13 of dimos/core/stream.py, manages incoming data reception. It stores an optional RemoteOut connection for cross-process communication and provides the subscribe() method to register callbacks that process incoming messages of type T.
Transport Wiring and Blueprint Orchestration
Stream objects remain inert until connected to a transport. The Module.set_transport method (lines 35-45 of dimos/core/module.py) attaches a transport implementation—such as LCM, pLCM, or DDS—to a specific stream, enabling actual data flow.
The Blueprint class orchestrates system-wide connectivity through Blueprint._connect_streams (line 86 of dimos/core/blueprints.py). This method groups streams sharing the same remapped name and type, creates or reuses the appropriate transport, and injects it into every participating module. This centralized wiring ensures that publishing on one Out[T] automatically delivers to every matching In[T] across the entire system topology.
Distributed Communication with Remote Links
When modules execute in separate processes or on different hosts, DimOS transparently bridges the communication gap. The In stream’s connection field points to a RemoteOut proxy object.
As implemented in dimos/core/stream.py, RemoteIn.connect (lines 55-56) and In.connect (line 40) establish this wiring. The remote side publishes through its local transport, while the local side receives data via the In[T] subscriber mechanism, making network distribution indistinguishable from local communication in the module implementation code.
Practical Implementation Example
The following example demonstrates velocity command streaming between two modules:
# my_module.py --------------------------------------------------------------
from dimos.core.module import Module
from dimos.core.stream import In, Out
from dimos.msgs.geometry_msgs import Twist
class CmdPublisher(Module):
# Outgoing velocity commands
cmd_vel: Out[Twist]
def start(self) -> None:
# Publish a command once per second (demo only)
import time
while True:
self.cmd_vel.publish(Twist(linear=Vector3(x=0.5), angular=Vector3()))
time.sleep(1)
class CmdConsumer(Module):
# Subscribe to velocity commands
cmd_vel: In[Twist]
def start(self) -> None:
# Register a callback that runs every time a command arrives
self.cmd_vel.subscribe(self.handle_cmd)
def handle_cmd(self, msg: Twist) -> None:
print(f"Received command: {msg}")
# -------------------------------------------------------------------------
# wiring ---------------------------------------------------------------
from dimos.core.blueprints import autoconnect
# Autoconnect parses the type hints, creates transports, and connects
blueprint = autoconnect(CmdPublisher.blueprint, CmdConsumer.blueprint)
module_coordinator = blueprint.build()
# -------------------------------------------------------------------------
# When the blueprint is built:
# * `CmdPublisher.cmd_vel` gets a transport (e.g. pLCM on topic /cmd_vel)
# * `CmdConsumer.cmd_vel` receives the *same* transport
# * Publishing on the Out side triggers `Transport.broadcast`, which delivers
# the message to the In side’s subscriber (`handle_cmd`).
This implementation functions identically whether both modules run in the same thread or distributed across Docker containers and physical robots, as the Transport abstraction handles protocol selection and serialization automatically.
Summary
- DimOS In[T] and Out[T] streams use Python type hints to declare communication interfaces without boilerplate configuration code.
- The
Modulebase class automatically instantiates stream objects by inspecting class annotations inmodule.py. - Transport abstraction allows the same code to operate over LCM, pLCM, DDS, or custom protocols without modification.
- Blueprint orchestration automatically wires matching stream pairs and injects shared transport objects.
- Remote linking via
RemoteOutandRemoteInenables transparent cross-process and cross-machine communication.
Frequently Asked Questions
How does DimOS ensure type safety between In[T] and Out[T] streams?
DimOS enforces type safety through Python's generic type system during the blueprint wiring phase. The Blueprint._connect_streams method validates that matching streams share identical type parameters T before establishing the connection, preventing runtime type mismatches that could corrupt data or cause serialization errors.
Can In[T] and Out[T] streams communicate across different physical machines?
Yes, the streaming layer transparently supports distributed communication. When modules run on separate hosts, the In[T] stream connects to a RemoteOut proxy that serializes data through the transport layer (such as LCM or DDS), delivering messages across the network without requiring changes to the module's publish/subscribe logic.
What transport protocols does DimOS support for stream communication?
According to the source code in dimos/core/module.py, DimOS supports multiple transport implementations including LCM (Lightweight Communications and Marshalling), pLCM (Python LCM bindings), and DDS (Data Distribution Service). The specific protocol is selected during blueprint configuration and injected via Module.set_transport.
How does DimOS handle multiple modules subscribing to the same Out[T] stream?
The Out[T] object maintains a list of local callbacks and a transport reference. When publish() is called, it broadcasts to all registered subscribers through Transport.broadcast, which fans out the message to every connected In[T] stream regardless of whether they reside in the same process or remote locations, implementing a true publish-subscribe pattern.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →