Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Proposal: Module deployment as Grounded Blueprints #2758

Description

@dimos-bot

Status: draft for review.

This is a proposal/RFC issue.

This note frames PR #2704 as one concrete step toward a broader module deployment model. The goal is not only Python dependency isolation. The larger goal is to let DimOS keep a stable module identity while different implementations run locally, remotely, or as native processes.

Problem

DimOS has two parallel module families today:

  • Python modules run through Python workers and get the full DimOS surface: streams, RPCs, skills, module refs, lifecycle, and blueprint wiring.
  • Native modules run as external binaries wrapped by a Python NativeModule. The Python wrapper owns blueprint wiring, lifecycle, topic assignment, config serialization, logging, and process supervision. The native process owns computation and pub/sub.

Both families are moving toward the same deployment pressure:

  • Python modules need isolated dependency environments.
  • Native modules need repeatable build and runtime environments.
  • Remote deployment needs code or binary sync.
  • Weak robot computers may need cross-compilation or prepared artifacts.
  • Native runtimes may need dynamic libraries, Nix closures, Pixi environments, or transport-specific setup.

The common problem is module deployment.

Current proof point

PR #2704 introduces a narrow proof point for Python modules:

  • A blueprint can register a Python runtime project.
  • A module contract can be placed into that runtime.
  • Deployment reconciles the locked runtime project before launch.
  • WorkerManagerPython dispatches placed modules into runtime-specific Python worker pools.
  • The worker launches the prepared .venv/bin/python and imports the runtime implementation.
  • The coordinator still sees the dependency-light module contract.

That gives us one concrete backend for a broader model: the module contract stays stable while execution moves into a backend-specific runtime.

Native branches point in the same direction

Recent native-module branches show the same shape from another angle:

  • Andrew's cpp-native-module-stdin work makes native config and topics serializable through stdin instead of only CLI flags.
  • Andrew's Rust transport work adds a native transport abstraction, including Zenoh.
  • Lesh's MLS/RPP work uses Rust native modules with cargo build --release and stdin_config=True.

Those branches are not the same feature as PR #2704, but they point at the same seam: DimOS needs a shared way to describe what a module is, what it needs, where it runs, and how deployment prepares it.

Core concepts

flowchart TD
    Package[Self-Contained Module Package]
    Contract[Module Contract]
    Impl[Implementation]
    Requirement[Runtime Requirement]
    Recipe[Preparation / Launch Recipes]

    Blueprint[Blueprint\nungrounded scaffold]
    Grounded[Grounded Blueprint?\nrunnable binding]
    Target[Execution Target Profile]
    Assignment[Deployment Assignment]
    Strategy[Preparation Strategy]
    Reconciler[Deployment Reconciler]

    Package --> Contract
    Package --> Impl
    Package --> Requirement
    Package --> Recipe

    Blueprint --> Grounded
    Package --> Grounded
    Target --> Grounded
    Assignment --> Grounded
    Strategy --> Grounded

    Grounded --> Reconciler
    Reconciler --> Prepare[prepare / build]
    Reconciler --> Sync[sync code, binary, or closure]
    Reconciler --> Launch[launch process]
    Reconciler --> Connect[connect streams, RPC, transports]
Loading

Self-Contained Module Package

A Self-Contained Module Package is the module-owned side of deployment. It carries the facts that should move with the module:

  • the dependency-light module contract
  • the Python implementation or native source/binary target
  • runtime and build declarations such as pyproject.toml, uv.lock, pixi.toml, flake.nix, Cargo.toml, or CMakeLists.txt
  • preparation recipes
  • launch recipe
  • optional smoke test

This should start as a layout convention, not a required manifest. Existing Python and native modules already have most of this structure.

Blueprint

A Blueprint should remain the ungrounded scaffold:

  • which modules exist
  • how streams and refs connect
  • what config surfaces exist
  • which module contracts participate in the stack

A Blueprint may contain portable deployment intent, but it should not hardcode one lab's SSH hosts, paths, credentials, or robot names.

Grounded Blueprint vs DeploymentSpec

The runnable binding needs a name. The current leaning is Grounded Blueprint rather than DeploymentSpec.

Reason:

  • Blueprint reads as an architectural scaffold.
  • A runnable stack needs that scaffold grounded into real targets, assignments, and preparation choices.
  • DeploymentSpec sounds like a separate ops artifact, while the current project already uses Python-configurable blueprints.

Open question: is Grounded Blueprint the right term, or should we keep DeploymentSpec for the lower-level resolved object?

Execution Target Profile

An Execution Target Profile is the machine-owned side of deployment. It should stay small.

It should include facts we cannot infer from the module package:

  • target identity
  • access kind: local, SSH, container, Kubernetes, etc.
  • architecture and OS family
  • deployment root and cache root
  • network identity and transport reachability
  • hard constraints such as read-only filesystem or no container runtime

It should not become an inventory of installable tools. If uv, pixi, nix, or cargo can be bootstrapped by the deployment workflow, the module package or preparation strategy should say how.

Preparation Strategy

Preparation Strategy is deployment-owned. It decides where and how to realize the module package's runtime requirement for a target.

Examples:

  • prepare directly on the execution target
  • sync source, then build remotely
  • build on the coordinator host, then sync artifacts
  • cross-compile on a builder, then sync the binary
  • build a Nix closure, then copy the closure
  • use a prebuilt artifact

Sync belongs inside the preparation strategy. Sync only makes sense relative to where preparation happens.

Stress-test cases

flowchart LR
    subgraph Case1[Python module]
      Pkg1[Python package\npyproject + uv/pixi/nix] --> Prep1[prepare on target]
      Prep1 --> Run1[run Python implementation]
    end

    subgraph Case2[Normal native module]
      Pkg2[Native package\nCargo / flake / pixi] --> Prep2[build on target]
      Prep2 --> Run2[run native binary]
    end

    subgraph Case3[Weak target native module]
      Pkg3[Native package] --> Prep3[cross-compile elsewhere]
      Prep3 --> Sync3[sync binary]
      Sync3 --> Run3[run on weak target]
    end

    subgraph Case4[Native binary plus runtime env]
      Pkg4[Native package\nsource + runtime env] --> Prep4[cross-compile binary]
      Pkg4 --> Env4[prepare/sync runtime closure]
      Prep4 --> Run4[run binary]
      Env4 --> Run4
    end
Loading

These cases argue for three separate concerns:

  1. the module-owned package and requirements
  2. the target-owned machine profile
  3. the deployment-owned assignment and preparation strategy

How this maps to current PR #2704

flowchart TD
    Contract[Module Contract\ncoordinator-visible identity]
    RuntimeImpl[Runtime Implementation\nsubclasses contract]
    RuntimeProject[Python Runtime Project\npyproject.toml + uv.lock]
    Placement[RuntimePlacement\ncontract -> runtime + implementation]

    Blueprint[Blueprint]
    Manager[WorkerManagerPython]
    Pool[Runtime Python Worker Pool]
    Launcher[CommandWorkerLauncher]
    Venv[prepared .venv/bin/python]
    Worker[python_worker._worker_entrypoint]

    Contract --> Blueprint
    RuntimeImpl --> RuntimeProject
    RuntimeProject --> Placement
    Placement --> Blueprint
    Blueprint --> Manager
    Manager --> Pool
    Pool --> Launcher
    RuntimeProject --> Venv
    Venv --> Launcher
    Launcher --> Worker
    Worker --> RuntimeImpl
    Contract -. RPC / streams / refs .-> Manager
Loading

The PR implements one local preparation strategy:

Python runtime project + prepare locally + launch prepared .venv Python

The broader model should let native modules and remote modules reuse the same shape without forcing them into Python runtime terminology.

Proposed direction

Start with Python APIs and conventions rather than a new declarative manifest.

Near term:

Blueprint
  remains the Python-configurable module scaffold

Self-Contained Module Package convention
  describes module-owned requirements and recipes

Grounded Blueprint? / DeploymentSpec?
  binds blueprint modules to targets and preparation strategies

Deployment Reconciler
  prepares, syncs, launches, and connects modules

Later:

dimos prepare <grounded-blueprint>
dimos run <grounded-blueprint>

For backward compatibility, a plain Blueprint can be implicitly grounded to the local target.

Open questions

  1. Should the runnable binding be called Grounded Blueprint or DeploymentSpec?
  2. How much portable deployment intent should remain on Blueprint itself?
  3. What is the smallest useful Execution Target Profile?
  4. Should each Self-Contained Module Package eventually get a manifest, or should layout conventions be enough?
  5. How should a Deployment Reconciler report the resolved plan before mutating remote machines?
  6. What native capabilities need the same contract boundary: config, transport descriptors, RPC/control plane, TF, logging, health?

Suggested narrative

Use this PR as a proof point, not as the whole story:

PR #2704 adds local Python runtime projects. More importantly, it introduces a seam between what DimOS sees and where a module implementation runs. That seam can grow into a shared deployment model for Python modules, native modules, and remote execution.

Links


Synced from DIM-1123

Metadata

Metadata

Assignees

No one assigned

    Labels

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions