Skip to main content

Blueprints

Blueprints (BlueprintAtom) are instructions for how to initialize a Module. You don’t typically want to run a single module, so multiple blueprints are handled together in Blueprint. You create a Blueprint from a single module (say ConnectionModule) with:
session=blueprint-ex1
But the same thing can be accomplished more succinctly as:
session=blueprint-ex1
Now you can create the blueprint with:
skip session=blueprint-ex1

Linking blueprints

You can link multiple blueprints together with autoconnect:
session=blueprint-ex1
blueprint itself is a Blueprint so you can link it with other modules:
session=blueprint-ex1
Blueprints are frozen data classes, and autoconnect() always constructs an expanded blueprint so you never have to worry about changes in one affecting the other.

Publishing external blueprints

DimOS can discover runnable blueprints from installed Python packages. External packages declare entry points in the dimos.blueprints group:
After the package is installed in the same Python environment as DimOS, users can run those blueprints by fully qualified name:
External names are always <canonical-distribution-namespace>.<external-local-blueprint-name>:
  • The namespace comes from the installed distribution name. DimOS lowercases it and collapses runs of -, _, and . into -, so My_Robot.Stack becomes my-robot-stack.
  • The local blueprint name is the entry point name. It must be lowercase kebab-case matching ^[a-z0-9]+(-[a-z0-9]+)*$, such as go2 or keyboard-teleop.
Entry point targets may be either:
  • a Blueprint object, such as a module-level go2_blueprint; or
  • a DimOS Module class, such as KeyboardTeleop, which DimOS converts with .blueprint().
dimos list includes external names from package metadata without importing the target modules. dimos run my-robot-stack.go2 imports only the requested entry point target. Remote coordinator resolution happens in the coordinator environment. If a client asks a coordinator to load my-robot-stack.go2, the my-robot-stack package must be installed where the coordinator performs name resolution; installing it only in the client environment is not enough.

Duplicate module handling

If the same module appears multiple times in autoconnect, the later blueprint wins and overrides earlier ones:
session=blueprint-ex1
This is so you can “inherit” from one blueprint but override something you need to change.

How transports are linked

Imagine you have this code:
session=blueprint-ex1
Connections are linked based on (property_name, object_type). In this case ('image', Image) will be connected between the two modules, but begin_explore will not be linked to start_explore.

Topic names

By default, the name of the property is used to generate the topic name. So for image, the topic will be /image. The property name is used only if it’s unique. If two modules have the same property name with different types, then both get a random topic such as /SGVsbG8sIFdvcmxkI. If you don’t like the name you can always override it like in the next section.

Which transport is used?

By default LCMTransport is used if the object supports lcm_encode. If it doesn’t pLCMTransport is used (meaning “pickled LCM”). You can override transports with the transports method. It returns a new blueprint in which the override is set.
session=blueprint-ex1
Note: expanded_blueprint does not get the transport overrides because it’s created from the initial value of base_blueprint, not the second.

Remapping connections

Sometimes you need to rename a connection to match what other modules expect. You can use remappings to rename module connections:
session=blueprint-ex2
After remapping:
  • The color_image output from ConnectionModule is treated as rgb_image
  • It automatically connects to any module with an rgb_image input of type Image
  • The topic name becomes /rgb_image instead of /color_image
If you want to override the topic, you still have to do it manually:
session=blueprint-ex2

Overriding global configuration.

Each module includes the global config available as self.config.g. E.g.:
session=blueprint-ex3
The config is normally taken from .env or from environment variables. But you can specifically override the values for a specific blueprint:
session=blueprint-ex3

Providing blueprint configuration to users

Blueprint.config() can be used to get a pydantic.BaseModel that can be used to inspect or test configuration settings that can be passed to Blueprint.build():
session=blueprint-ex1
dimos.robot.cli.dimos.arg_help() is a helper function that will return a string containing all details of these arguments (this is how the output is produced when running dimos run unitree-go2 --help, for example):
session=blueprint-ex1
Another function is dimos.robot.cli.dimos.load_config_args() which can create the argument dict for users from a config file, environment variables and CLI arguments:
session=blueprint-ex1

Calling the methods of other modules

Imagine you have this code:
session=blueprint-ex3
And you want to call ModuleA.get_time in ModuleB.request_the_time. To do this, you can request a module reference.
session=blueprint-ex3
But what if we want HelperModule to work for more than just Drone? For that we can use a spec.
session=blueprint-ex3

Optional module references

If a dependency might not be present in every blueprint, annotate it as SomeSpec | None = None. The blueprint will try to resolve it but won’t raise if no matching module is found:
session=blueprint-ex3

Defining skills

Skills are methods on a Module decorated with @skill. The agent automatically discovers all skills from launched modules at startup.
session=blueprint-ex4

Building

All you have to do to build a blueprint is call:
skip session=blueprint-ex4
This returns a ModuleCoordinator instance that manages all deployed modules.

Running and shutting down

You can block the thread until it exits with:
skip session=blueprint-ex4
This will wait for Ctrl+C and then automatically stop all modules and clean up resources.