Skip to content

Add a custom tool

Extend a running stack with your own tool: add it to the project's Python package, wire it into a room, exercise it, and cover it with a test. This continues from First steps.

Prerequisites

1. Add a tool

Your project is an installable Python package; tools live in src/<package>/tools.py (the greeting tool from First steps is there). Add a sibling:

# src/<package>/tools.py
def farewell(name: str) -> str:
    """Return a friendly farewell for ``name``."""
    return f"Goodbye, {name}! Come back soon."

The docstring matters: the LLM uses it as the tool's description.

2. Wire it into the custom room

Add the new tool to backend/environment/rooms/custom/room_config.yaml:

tools:
  - tool_name: "<package>.tools.greeting"
  - tool_name: "<package>.tools.farewell"

The backend runs with --reload=config, so saving this config change restarts it — which also re-imports your edited tools.py, picking up farewell. (If it doesn't appear, docker compose restart backend.)

3. Test it in the room

Open the Custom Tool Demo room and ask:

Please say farewell to Ada.

The agent calls your new tool and replies:

Goodbye, Ada! Come back soon.

4. Add a unit test

The generated project is also a normal Python package with a test suite already wired up: tests/unit/test_tools.py covers greeting. Add a case for farewell beside it (tools is already imported at the top of that file):

# tests/unit/test_tools.py
def test_farewell_includes_name():
    result = tools.farewell("Ada")

    assert "Ada" in result

Create the dev environment once, then run the suite:

uv sync          # installs the dev dependencies, incl. pytest
uv run pytest

No setup is needed: pyproject.toml already declares pytest, puts src/ on the path, and points testpaths at tests/unit/, so your new test is collected and passes.

5. Commit it

git add src/<package>/tools.py tests/unit/test_tools.py \
    backend/environment/rooms/custom/room_config.yaml
git commit -m "Add a farewell tool (with a test) to the custom room"

Where next

That completes the core series: Next steps collects the optional walkthroughs you can take from here.

Related: Work with Gitea ships a change like the one you just made through a pull request hosted by the stack's own Gitea.