Skip to main content

Creating a Plugin

Plugin Interface

Every plugin corresponds to the Plugin class:
from typing import Callable, List
from hedera_agent_kit.shared.configuration import Context
from hedera_agent_kit.shared.tool import Tool

class Plugin:
    def __init__(
        self,
        name: str,
        tools: Callable[[Context], List[Tool]],
        version: str | None = None,
        description: str | None = None,
    ):
        # ...

Tool Interface

Each tool must assume the Tool class structure:
from abc import ABC, abstractmethod
from typing import Any, Type
from hiero_sdk_python import Client
from pydantic import BaseModel
from hedera_agent_kit.shared.configuration import Context
from hedera_agent_kit.shared.models import ToolResponse

class Tool(ABC):
    method: str
    name: str
    description: str
    parameters: Type[BaseModel]

    @abstractmethod
    async def execute(
        self, client: Client, context: Context, params: Any
    ) -> ToolResponse:
        """Execute the tool logic."""
        pass
See hedera_agent_kit/shared/tool.py for the full definition.
This is NOT a breaking change. BaseToolV2 is an abstract class that implements the Tool interface — plain Tool implementations continue to work exactly as before. However, they do not support the hooks and policies system (e.g., HcsAuditTrailHook, MaxRecipientsPolicy, RejectToolPolicy). To enable those features, migrate your tool to BaseToolV2.
Extending BaseToolV2 splits execution into a 7-stage lifecycle that hooks and policies tap into automatically. For complete step-by-step instructions, see the Python ToolV2 Migration Guide.
def tool(context: Context) -> Tool:
    return Tool(
        method=MY_TOOL,
        name="My Custom Tool",
        description=my_tool_prompt(context),
        parameters=MyToolParams,
        execute=my_tool_execute, # all logic in one function
    )
Aspectv3 (Legacy)v4 (BaseToolV2)
DeclarationFunctional factory (Tool(...))Class extending BaseToolV2
Lifecycle stagesAll inside a single execute()normalize_paramscore_actionsecondary_action
Hook/Policy support✗ None✓ Automatic at stages 1, 3, 5, 7
Breaking change?No

Creating a Plugin

Step 1: Create Plugin Structure

my_custom_plugin/
├── __init__.py           # Plugin exports
├── plugin.py             # Plugin definition
└── tools/
    └── my_tool.py        # Individual tool implementation

Step 2: Implement Your Tool

# tools/my_tool.py
from typing import Any
from pydantic import BaseModel, Field
from hiero_sdk_python import Client
from hedera_agent_kit.shared.configuration import Context
from hedera_agent_kit.shared.models import ToolResponse
from hedera_agent_kit.shared.tool_v2 import BaseToolV2
from hedera_agent_kit.shared.strategies.tx_mode_strategy import handle_transaction

class MyToolParams(BaseModel):
    required_param: str = Field(..., description="Description of required parameter")
    optional_param: str = Field(None, description="Description of optional parameter")

def my_tool_prompt(context: Context = None) -> str:
    return """
    This tool performs a specific operation.
    
    Parameters:
    - required_param (string, required): Description
    - optional_param (string, optional): Description
    """

MY_TOOL = "my_tool"

class MyCustomTool(BaseToolV2):
    def __init__(self, context: Context):
        self.method: str = MY_TOOL
        self.name: str = "My Custom Tool"
        self.description: str = my_tool_prompt(context)
        self.parameters: type[MyToolParams] = MyToolParams

    async def normalize_params(
        self, params: Any, context: Context, client: Client
    ) -> MyToolParams:
        # Stage 2: normalize/validate params
        return params

    async def core_action(
        self,
        normalized_params: MyToolParams,
        context: Context,
        client: Client,
    ) -> Any:
        # Stage 4: build the transaction or run the query
        return await some_hedera_operation(normalized_params)

    async def secondary_action(
        self, result: Any, client: Client, context: Context
    ) -> ToolResponse:
        # Stage 6: sign and submit
        return await handle_transaction(result, client, context)

    async def handle_error(self, error: Exception, context: Context) -> ToolResponse:
        # Optional: override for tool-specific error messages
        message: str = f"Operation failed: {str(error)}"
        print(f"[{self.method}]", message)
        return ToolResponse(human_message=message, error=message)

def tool(context: Context) -> BaseToolV2:
    return MyCustomTool(context)

Step 3: Create Plugin Definition

# plugin.py
from hedera_agent_kit.shared.types import Plugin, Context
from .tools.my_tool import tool as my_tool, MY_TOOL

my_custom_plugin = Plugin(
    name="my-custom-plugin",
    version="1.0.0",
    description="A plugin for custom functionality",
    tools=lambda context: [my_tool(context)],
)

my_custom_plugin_tool_names = {
    "MY_TOOL": MY_TOOL,
}

Using Your Plugin

from hedera_agent_kit.langchain.toolkit import HederaLangchainToolkit
from hedera_agent_kit.shared.configuration import Configuration, Context, AgentMode
from my_custom_plugin import my_custom_plugin

configuration = Configuration(
    tools=[],
    plugins=[
        my_custom_plugin,
    ],
    context=Context(
        mode=AgentMode.AUTONOMOUS,
        account_id=str(operator_id),
    ),
)

hedera_toolkit = HederaLangchainToolkit(
    client=client,
    configuration=configuration,
)

tools = hedera_toolkit.get_tools()

Publish and Register Your Plugin

To create a plugin to be use with the Hedera Agent Kit, you will need to create a plugin in your own repository, publish an npm package, and provide a description of the functionality included in that plugin, as well as the required and optional parameters. Once you have a repository, published npm package, and a README with a description of the functionality included in that plugin in your plugin’s repo, as well, add it to the Hedera Agent Kit by forking and opening a Pull Request that includes:
  1. Include the plugin as a bullet point under the Third Party Plugin section in the README.md in the hedera-agent-kit-py.
    • Include the name, a brief description, and a link to the repository with the README, as well the URL linked to the published npm package.
  2. If you would like to include your plugin functionality in the Hedera plugin built for ElizaOS simply make a PR to add your plugin name to the plugins array in the Hedera ElizaOS plugin where the configuration is initiated. The hedera-agent-kit adaptor architecture means your plugin functionality will be usable with no additional configuration needed.
Please also reach out in the Hedera Discord in the Support > developer-help-desk channel or create an Issue in this repository for help building, publishing, and promoting your plugin.

Plugin README Template

## Plugin Name
This plugin was built by <?> for the <project, platform, etc>. It was built to enable <who?> to <do what?>

_Feel free to include a description of your project and how it can be used with the Hedera Agent Kit. 

### Installation

```bash
npm install <plugin-name>
```

### Usage

```javascript
import { myPlugin } from '<plugin-name>';
```

```javascript
 const hederaAgentToolkit = new HederaLangchainToolkit({
    client,
    configuration: {
      context: {
        mode: AgentMode.AUTONOMOUS,
      },
      plugins: [coreTokenPlugin, coreAccountPlugin, coreConsensusPlugin, coreAccountQueryPlugin, coreConsensusQueryPlugin, coreTokenQueryPlugin, myPlugin],
    },
  });
```

### Functionality
Describe the different tools or individual pieces of functionality included in this plugin, and how to use them.

**Plugin Name**
_High level description of the plugin_

| Tool Name                                       | Description                                        |Usage                                             |
| ----------------------------------------------- | -------------------------------------------------- |--------------------------------------------------------- |
| `YOUR_PLUGIN_TOOL_NAME`| What it does | How to use. Include a list of parameters and their descriptions|

Resources

Examples

Examples and References