Skip to content

Tools

Tools are async functions the agent can call. Register them with @app.tool().

Basic tool

from langclaw import Langclaw

app = Langclaw()

@app.tool()
async def get_weather(city: str) -> dict:
    """Get current weather for a city."""
    # real implementation: call a weather API
    return {"city": city, "temp": 22, "condition": "sunny"}

The function name becomes the tool name. The docstring becomes the tool description shown to the LLM.

Error handling

Tools must return error dicts — never raise into the agent:

@app.tool()
async def fetch_data(url: str) -> dict:
    """Fetch JSON from a URL."""
    try:
        async with httpx.AsyncClient() as client:
            r = await client.get(url)
            r.raise_for_status()
            return r.json()
    except Exception as e:
        return {"error": str(e)}  # correct
        # raise  # wrong — breaks the agent loop

Custom tool name

By default the tool name is the function name. To use a different name, pre-wrap the function with LangChain's @tool("name")@app.tool() registers an existing BaseTool as-is:

from langchain_core.tools import tool

@app.tool()
@tool("search_web")
async def _search(query: str) -> list[dict]:
    """Search the web for a query."""
    ...

Bring an existing LangChain tool

Any LangChain BaseTool instance drops in via register_tool() (or register_tools([...]) for several at once) — this is how you reuse the LangChain tool ecosystem:

from langchain_community.tools import DuckDuckGoSearchRun

app.register_tool(DuckDuckGoSearchRun())
app.register_tools([tool_a, tool_b], roles=["analyst"])  # optional RBAC grant

@app.tool() is sugar for "wrap this function, then register it"; register_tool() skips the wrapping for tools you already built.

Built-in tools

Langclaw ships built-in tools under langclaw.agents.tools. They're wired automatically when the relevant config is set:

Tool Extra required Config key
web_search search LANGCLAW__TOOLS__BRAVE_API_KEY (default backend) — see note
web_fetch search
read_email / search_emails / send_email / draft_email / reply_email / manage_labels gmail LANGCLAW__TOOLS__GMAIL__ENABLED=true (+ OAuth client)
cron LANGCLAW__CRON__ENABLED=true
task subagents registered
eval interpreter LANGCLAW__INTERPRETER__ENABLED=true

web_search needs a backend key

The default search backend is brave, which requires LANGCLAW__TOOLS__BRAVE_API_KEY. Set LANGCLAW__TOOLS__SEARCH_BACKEND=tavily (with …TAVILY_API_KEY) or =duckduckgo (no key required) to switch. Without a usable backend, web_search is silently omitted from the toolset.

RBAC

Tools participate in the three-axis RBAC system. See the RBAC guide for role definitions that gate tool access.