How to Write LangGraph-Based Agents that Utilize Skill Containers in DimOS

DimOS provides a LangGraph-based Agent that automatically converts methods decorated with @skill into LangChain tools, enabling LLM-driven execution of robot capabilities through a compiled state graph.

The dimensionalOS/dimos repository ships with a powerful framework for building LangGraph-based agents that utilize skill containers. By decorating methods with @skill and inheriting from the base Module class, developers can expose robot capabilities as LLM-callable tools without manual plumbing.

Understanding Skill Containers and the @skill Decorator

Skill containers are standard DimOS modules that expose public methods decorated with @skill. The decorator, defined in dimos/agents/annotation.py, marks methods as both RPC-callable and LLM-exposed tools.

Key Requirements for Skill Methods

Every skill method must include:

  • A descriptive docstring (used as the tool description)
  • Type-annotated parameters (used to build the JSON schema)

Example Skill Container Implementation

from dimos.agents.annotation import skill
from dimos.core.core import rpc
from dimos.core.module import Module

class CalculatorSkill(Module):
    @rpc
    def start(self) -> None:
        super().start()

    @skill
    def add(self, x: float, y: float) -> str:
        """Return the sum of x and y."""
        return str(x + y)

calculator = CalculatorSkill.blueprint

Building LangGraph-Based Agents with autoconnect

The Agent class in dimos/agents/agent.py serves as the LangGraph runner. It discovers skills from loaded modules, converts them to LangChain tools, and compiles a state graph for LLM interaction.

Blueprint Composition

Use the autoconnect helper from dimos/core/blueprints.py to wire skill containers to the Agent:

from dimos.agents.agent import Agent
from dimos.core.blueprints import autoconnect
from my_skill import calculator

blueprint = autoconnect(calculator, Agent.blueprint)

if __name__ == "__main__":
    blueprint.build().loop()

Tool Discovery and Conversion

When the blueprint builds, Agent.on_system_modules receives RPC clients and calls _get_tools_from_modules. This method:

  1. Invokes module.get_skills() to retrieve SkillInfo objects (defined in dimos/core/module.py)
  2. Transforms each skill using _skill_to_tool into a LangChain StructuredTool
  3. Passes the tool list to langchain.agents.create_agent to generate a CompiledStateGraph

Runtime Architecture and Message Flow

Once running, the Agent manages a continuous loop between human input and LLM execution:

  1. Input Handling: Human messages arrive via the human_input stream and are queued as HumanMessage objects
  2. Graph Execution: The Agent thread calls state_graph.stream({"messages": history}, stream_mode="updates")
  3. Tool Invocation: When the LLM selects a tool, the wrapped RPC call executes the skill in its original module via RpcCall
  4. Output Publishing: Results (including images or audio via agent_encode()) append to message history and publish to the agent output stream

The Agent also exposes an agent_idle boolean for monitoring execution state.

Remote Access via MCP Server

For external LLM agents, dimos.agents.mcp.mcp_server.McpServer automatically exposes all @skill tools over HTTP. This enables remote agents to invoke DimOS skills without running the in-process LangGraph Agent.

Summary

  • Skill containers are Module subclasses with @skill decorated methods
  • The Agent automatically discovers skills and converts them to LangChain tools via _get_tools_from_modules and _skill_to_tool
  • Use autoconnect from dimos/core/blueprints.py to compose skill containers with the Agent
  • The resulting CompiledStateGraph streams messages between the LLM and skills through the internal RPC system
  • Skills returning objects with agent_encode() automatically publish multimedia artefacts to the chat history

Frequently Asked Questions

What is the difference between @rpc and @skill decorators?

The @rpc decorator (from dimos.core.core) marks methods as callable via the internal RPC system. The @skill decorator (from dimos.agents.annotation) extends this by also exposing the method as a LangChain tool for LLM agents. All @skill methods must also be @rpc enabled, but not all RPC methods need to be skills.

How does the Agent handle type annotations for tool schemas?

The Agent uses the type annotations and docstring from each @skill method to construct the tool schema. Specifically, _skill_to_tool in dimos/agents/agent.py inspects the SkillInfo object (created in dimos/core/module.py) which captures the method's signature. This schema is passed to LangChain's StructuredTool to ensure the LLM receives proper JSON schema definitions for arguments.

Can I use skill containers without the LangGraph Agent?

Yes. Skill containers function as standard DimOS modules and can be invoked directly via RPC calls or exposed through the MCP server (dimos/agents/mcp/mcp_server.py). The MCP server automatically discovers all @skill methods and serves them over HTTP, allowing external LLM agents to invoke DimOS capabilities without instantiating the in-process LangGraph-based Agent.

What happens if a skill returns complex data like images?

Skills returning objects that implement agent_encode() (such as images or audio) automatically have their outputs processed by the Agent's _append_image_to_history method (in dimos/agents/agent.py). The encoded artefacts are appended to the message history and published to the agent output stream, allowing the LLM to receive multimodal context in subsequent turns.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →