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

> Learn to write LangGraph-based agents in DimOS that leverage skill containers. Automatically convert @skill methods into LangChain tools for LLM-driven robot capabilities and compiled state graphs.

- Repository: [Dimensional/dimos](https://github.com/dimensionalOS/dimos)
- Tags: how-to-guide
- Published: 2026-03-15

---

**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`](https://github.com/dimensionalOS/dimos/blob/main/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

```python
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`](https://github.com/dimensionalOS/dimos/blob/main/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`](https://github.com/dimensionalOS/dimos/blob/main/dimos/core/blueprints.py) to wire skill containers to the Agent:

```python
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`](https://github.com/dimensionalOS/dimos/blob/main/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`](https://github.com/dimensionalOS/dimos/blob/main/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`](https://github.com/dimensionalOS/dimos/blob/main/dimos/agents/agent.py) inspects the `SkillInfo` object (created in [`dimos/core/module.py`](https://github.com/dimensionalOS/dimos/blob/main/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`](https://github.com/dimensionalOS/dimos/blob/main/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`](https://github.com/dimensionalOS/dimos/blob/main/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.