Academy → Developer GuideOfficial documentation · Arabic guidance

Adding Tools

إضافة أداة جديدة

Advanced4 min readLesson 33 questions✓ 2026-08-18
Before you read

What this page is, and what it holds.

This page covers Adding Tools. It carries a source warning and takes about 4 minutes to read. Every tool opens a door. Write, delete, and send deserve a pause before you enable them.

9sections
5code examples
0tables
0commands
748source words
The official one-line description

How to add a new tool to Hermes Agent — schemas, handlers, registration, and toolsets

What you will be able to do

Outcomes taken from this page, not a template.

  • Understand what الأدوات is and when you need it.
  • Set WEATHER_API_KEY in the right place.
  • Avoid the mistake the source warns about.
Identifiers you will meet

Exactly as they appear in Hermes.

Environment variables
  • WEATHER_API_KEY
  • WEATHER_SCHEMA
  • OPTIONAL_ENV_VARS
Page map

Jump to the part you need.

  1. 01Overview
  2. 02Step 1: Create the Built-in Tool File
  3. 03Step 2: Add the Built-in Tool to a Toolset
  4. 04~~Step 3: Add Discovery Import~~ (No longer needed)
  5. 05Async Handlers
  6. 06Handlers That Need taskid
  7. 07Agent-Loop Intercepted Tools
  8. 08Optional: Setup Wizard Integration
  9. 09Checklist
The full official page

Nothing summarised away.

The documentation body below is reproduced from the official source so commands and identifiers stay exact. Each section carries a short note describing what it contains.

Before writing a tool, ask yourself: should this be a skill instead?

Make it a Skill when the capability can be expressed as instructions + shell commands + existing tools (arXiv search, git workflows, Docker management, PDF processing).

Make it a Tool when it requires end-to-end integration with API keys, custom processing logic, binary data handling, or streaming (browser automation, TTS, vision analysis).

Overview

Explains the idea itself. Read it slowly; the later sections build on it.

Adding a tool touches 2 files:

  1. tools/your_tool.py — handler, schema, check function, registry.register() call
  2. toolsets.py — add tool name to _HERMES_CORE_TOOLS (or a specific toolset)

Any tools/*.py file with a top-level registry.register() call is auto-discovered at startup — no manual import list required.

Step 1: Create the Built-in Tool File

Carries a warning. Read it before running anything here. The upstream warning appears below.

Every tool file follows the same structure:

Python69 lines
# tools/weather_tool.py
"""Weather Tool -- look up current weather for a location."""





logger = logging.getLogger(__name__)


# --- Availability check ---

def check_weather_requirements() -> bool:
    """Return True if the tool's dependencies are available."""
    return bool(os.getenv("WEATHER_API_KEY"))


# --- Handler ---

def weather_tool(location: str, units: str = "metric") -> str:
    """Fetch weather for a location. Returns JSON string."""
    api_key = os.getenv("WEATHER_API_KEY")
    if not api_key:
        return json.dumps({"error": "WEATHER_API_KEY not configured"})
    try:
        # ... call weather API ...
        return json.dumps({"location": location, "temp": 22, "units": units})
    except Exception as e:
        return json.dumps({"error": str(e)})


# --- Schema ---

WEATHER_SCHEMA = {
    "name": "weather",
    "description": "Get current weather for a location.",
    "parameters": {
        "type": "object",
        "properties": {
            "location": {
                "type": "string",
                "description": "City name or coordinates (e.g. 'London' or '51.5,-0.1')"
            },
            "units": {
                "type": "string",
                "enum": ["metric", "imperial"],
                "description": "Temperature units (default: metric)",
                "default": "metric"
            }
        },
        "required": ["location"]
    }
}


# --- Registration ---

from tools.registry import registry

registry.register(
    name="weather",
    toolset="weather",
    schema=WEATHER_SCHEMA,
    handler=lambda args, **kw: weather_tool(
        location=args.get("location", ""),
        units=args.get("units", "metric")),
    check_fn=check_weather_requirements,
    requires_env=["WEATHER_API_KEY"],
)

Key Rules

Step 2: Add the Built-in Tool to a Toolset

Ordered, practical steps. Run one and confirm it worked before moving on.

In toolsets.py, add the tool name:

Python12 lines
# If it should be available on all platforms (CLI + messaging):
_HERMES_CORE_TOOLS = [
    ...
    "weather",  # <-- add here
]

# Or create a new standalone toolset:
"weather": {
    "description": "Weather lookup tools",
    "tools": ["weather"],
    "includes": []
},

~~Step 3: Add Discovery Import~~ (No longer needed)

Ordered, practical steps. Run one and confirm it worked before moving on.

Tool modules with a top-level registry.register() call are auto-discovered by discover_builtin_tools() in tools/registry.py. No manual import list to maintain — just create your file in tools/ and it's picked up at startup.

Async Handlers

Settings you configure once. Change one at a time so you can see what each does. Set WEATHER_SCHEMA in your environment, not in the chat.

If your handler needs async code, mark it with is_async=True:

Python13 lines
async def weather_tool_async(location: str) -> str:
    async with aiohttp.ClientSession() as session:
        ...
    return json.dumps(result)

registry.register(
    name="weather",
    toolset="weather",
    schema=WEATHER_SCHEMA,
    handler=lambda args, **kw: weather_tool_async(args.get("location", "")),
    check_fn=check_weather_requirements,
    is_async=True,  # registry calls _run_async() automatically
)

The registry handles async bridging transparently — you never call asyncio.run() yourself.

Handlers That Need taskid

Explains the idea itself. Read it slowly; the later sections build on it.

Tools that manage per-session state receive task_id via **kwargs:

Python9 lines
def _handle_weather(args, **kw):
    task_id = kw.get("task_id")
    return weather_tool(args.get("location", ""), task_id=task_id)

registry.register(
    name="weather",
    ...
    handler=_handle_weather,
)

Agent-Loop Intercepted Tools

Explains the idea itself. Read it slowly; the later sections build on it.

Some tools (todo, memory, session_search, delegate_task) need access to per-session agent state. These are intercepted by run_agent.py before reaching the registry. The registry still holds their schemas, but dispatch() returns a fallback error if the intercept is bypassed.

Optional: Setup Wizard Integration

Ordered, practical steps. Run one and confirm it worked before moving on.

If your tool requires an API key, add it to hermes_cli/config.py:

Python10 lines
OPTIONAL_ENV_VARS = {
    ...
    "WEATHER_API_KEY": {
        "description": "Weather API key for weather lookup",
        "prompt": "Weather API key",
        "url": "https://weatherapi.com/",
        "tools": ["weather"],
        "password": True,
    },
}

Checklist

Settings you configure once. Change one at a time so you can see what each does. Set OPTIONAL_ENV_VARS in your environment, not in the chat.

  • [ ] Tool file created with handler, schema, check function, and registration
  • [ ] Added to appropriate toolset in toolsets.py
  • [ ] Confirmed this really should be a built-in/core tool and not a plugin
  • [ ] Handler returns JSON strings, errors returned as {"error": "..."}
  • [ ] Optional: API key added to OPTIONAL_ENV_VARS in hermes_cli/config.py
  • [ ] Optional: Added to toolset_distributions.py for batch processing
  • [ ] Tested with hermes chat -q "Use the weather tool for London"
Knowledge check

3 questions answered by this page alone.

Every option is a real identifier from the Hermes documentation. The wrong ones are real too, just from other pages.

1. Which of these environment variables actually appears in this lesson?
2. Which warning does the source state in this lesson?
3. Which of these headings does not appear in this lesson?