Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions dimos/spec/pyapi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# Will implement first blueprint level API as first pass and then module level API later. Because additional changes to core needed to handle LCM init for example if im just running `bla = dimos.connect("UnitreeGo2Connection")` unless we just make sure the agent inits LCM via the command line itself?

So proposed initial pass:

# Simple Example
```python
import dimos

# Normal start and connect
unitree_app = dimos()
> Returns static PER APP UUID inline for agent to save in memory
Copy link
Copy Markdown
Contributor Author

@leshy leshy Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if doing apps can stay in Py and not depend on memorizing random long strings, use python namespacing, something like

dimos.apps.myapp = dimos()

you can refer to
dimos.apps.myapp any time

or you can

dimos.ls() or dimos.apps.myapp.ls()


# Run from all_blueprints.py
unitree_app.run("unitree-g2-basic-blueprint")

# Run as a blueprint object
unitree_app.run(unitree_blueprint)

# Add a additional module that autoconnects dynamically, Returns failed topics that cant find connections
unitree_app.run(yolo_detector_module)

Copy link
Copy Markdown
Contributor Author

@leshy leshy Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

avoid random long strings like UUID and matching, instead of app stuff, deal with actual python objects,

most of above can be replaced by:

go2 = dimos.deploy(blueprints.unitree_g2)

then you could do

dimos.deploy(yolo_detector_module)

or (idk if needed - are apps namespaced or not? do apps talk to each other?):

go2.deploy(yolo_detector_module)

print(app.get_skills())
unitree_app.run_skill("observe")()
Copy link
Copy Markdown
Contributor Author

@leshy leshy Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes I get the angle, idea behind blueprints was that they behave same as modules on some level. so a blueprint has RPCs, skills, inputs, outputs, and can be treated as such by autoconnect, autoconnect doesn't need to know it's a set of modules. caller of skills or RPCs doesn't need to know either. so yes I agree with this, but

I'm not sure if we should be differentiating between skills and RPCs but we can.
either way, don't invent a new function calling API with

unitree_app.run_skill("observe")()

python has a perfect api for "calling functions" - it's called functions

go2.observe()

if blueprint (deployed or not!) behaves as a module on the outside you should have all the same helpers

print(go2.inputs)
print(go2.rpcs)
print(go2.skills)
go2.patro()

> returns string observation

unitree_app.run_skill("relative_move")(distance=1m)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

go2.relative_move(1.0)

```

# Add another module to the app from above after the fact
```python

# Connect to existing app from above

# Agent forgot what the UUID was lets check
dimos ls
> Returns latest UUID
unitree_app_2 = dimos(uuid)
unitree_app_2.run("openclaw-agent")
```
Copy link
Copy Markdown
Contributor Author

@leshy leshy Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup let's not give opportunity to anyone to forget UUIDs

dimos.ls()
> [go2]

or can have a namespace if you want, oneliner to access

dimos.apps.go2 = dimos.deploy(blueprints.go2)

in other script

dimos.apps.go2...


# Creating a module inline / import new module
```python

# Option 1: write a module inline
class Module1(Module):
...

# Option 2: import
import dimos
import yolo_detection_module

# NEW dimos application
drone_app = dimos()

app.run(yolo_detection_module)

app.remapping(/video, /color_image)
Copy link
Copy Markdown
Contributor Author

@leshy leshy Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't create another remapping API, blueprints offer this, make sure you are using the same code, potentially fix the API


app.stop()
```

# Other utilities (pretend they are python)

```python

dimos ls
> App ID | blueprint name | time_started | time running | active/inactive
> xxxx | bla1
> xxxx
Copy link
Copy Markdown
Contributor Author

@leshy leshy Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't use strings, always return actual objects that we can interact with

for deployed in dimos.ls():
    print(deployed)
    deployed.stop()

etc

for nice cli strings override __repr__ or __str__


dimos.killall # forced
dimos.stopall # graceful

# App operations
dimos <app-id> list
> Module ID | blueprint name | time_started | time running | active/inactive
> xxxx | bla1
> xxxx
dimos <app-id> log tail
dimos <app-id> log head <lines>
dimos <app-id> stop
dimos <app-id> kill
dimos <app-id> restart

# Module operations
dimos <app-id> <module-id> log tail
dimos <app-id> <module-id> log head <lines>
dimos <app-id> <module-id> stop
dimos <app-id> <module-id> kill
dimos <app-id> <module-id> restart

# Remapping
dimos <app-id> remap.('/video', '/color_image')





## Dimensional Applications

```
Application (top level — live, long-running instance)
└── Blueprint (predefined module groups / "run files")
└── Module (pub/sub primitive)
```

### Key properties of Applications:

1. **Composition**: An Application can compose multiple blueprints + individual modules. e.g. one blueprint + five standalone modules, or two blueprints together.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's what blueprint can do already


2. **Long-running**: Applications persist and you can hot-add modules to a running application as you debug/iterate.
Copy link
Copy Markdown
Contributor Author

@leshy leshy Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Paul is adding this to blueprints right now


4. **Transport & Remapping**: Applications should be able to do transport mapping and remappings, similar to how blueprints do it today. (Remapping at application level is a future pass.)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blueprints do this


5. **Relationship to Blueprints**: Blueprints are templates / "run files" that people define. Applications are live instances that consume blueprints. As you construct applications, they can functionally replace blueprints in many cases, but blueprints remain the portable, shareable unit.
Copy link
Copy Markdown
Contributor Author

@leshy leshy Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Paul does return an object when you deploy a blueprint, use that object, that's your app. I'd still call it "deployed blueprint" but we can call it apps, idk if confusing to have 2 names for activated/deactivated entity


6. **Modules as primitives**: Modules remain the core pub/sub primitive. Applications orchestrate them.

### How this maps to the Python API:

```python
import dimos

# Create an application
app = dimos()

# Run a blueprint (adds all its modules to the app)
app.run("unitree-go2-basic")

# Hot-add a standalone module
app.run(yolo_detector_module)

# Compose multiple blueprints
app.run("unitree-go2-basic")
app.run("openclaw-agent")

# Skills come from all modules in the app
app.get_skills()
app.run_skill("observe")()

app.stop()
```
Loading