Skip to main content
When you ask for tools=["read_notes"], PraisonAI checks four places in a fixed order and stops at the first match.
The user lists a tool by name on Agent(…); PraisonAI resolves it through local files, built-ins, praisonai-tools, then plugins.

How It Works

The same pipeline runs for Agent(tools=[...]), LocalManagedAgent(config=LocalManagedConfig(tools=[...])), YAML tools:, and CLI --tools.

Quick Start

1

Enable Local Tools

Set the environment variable to allow loading local tool files:
2

Create a Local Tool

Create tools.py in your project directory:
3

Declare tools by name on your Agent

4

PraisonAI resolves through the 4-layer pipeline

PraisonAI finds read_notes from your local tools.py (Tier 1) and internet_search from the built-in SDK (Tier 2) — no extra configuration needed.

How It Works

The user names a tool; PraisonAI walks the four tiers in order and stops at the first match.

The Four Tiers

From the tool_resolver.py module docstring — first match wins: Tier 1 now covers three concrete locations: (a) ./tools.py at your CWD, (b) a ./tools/ folder, and (c) .praisonai/tools/*.py — walked from the project up to the git root, plus ~/.praisonai/tools/*.py user-global. The .praisonai/tools/ layer is auto-loaded on praisonai run with no --tools flag; see Project-Local Tools.

Runtime string-name resolution inside an Agent

The four tiers above cover config-time resolution — tools.py/YAML names loaded by the CLI’s praisonai_code.tool_resolver. When you pass a tool name as a string to Agent(tools=[...]), the agent runtime uses a separate 3-tier resolver in praisonaiagents.tools.resolver at execution time.
internet_search resolves from built-in TOOL_MAPPINGS; my_registered_tool resolves from the tool registry if you registered it. With only built-ins installed, the first name works out of the box. The runtime resolver walks three tiers — first match wins: If a name resolves nowhere, the resolver logs a warning and skips it — the agent keeps running. A partially-installed or broken praisonai-tools no longer crashes the run either: the resolver flips its “available” flag off and continues.
The runtime 3-tier resolver is safe to use even if praisonai_tools is only partially installed — a broken import no longer takes the agent down.
Use the 4-tier CLI resolver for tools.py/YAML config-time names, and the 3-tier runtime resolver for Agent(tools=["name"]) string names at execution time. They are different modules that solve different problems.

Precedence Example

If you define def search(...) in your local tools.py and there is also a search in praisonai-tools, the local one wins — Tier 1 always beats Tier 3. To see which tier resolved a tool, run with LOGLEVEL=INFO:
The log shows: Resolved 'search' from source 'local-tools.py'

When praisonai-tools Is Not Installed

As of PR #2550, failures from the praisonai-tools package are logged, not silently skipped. You’ll see them at LOGLEVEL=INFO:
This means tool resolution failures are now visible and debuggable, rather than passing silently through to an unresolved tool error at runtime.

YAML tools: Blocks

resolve_all_from_yaml walks both the top-level tools: list and the agents: shape, so both formats work:
Tasks nested under agents can also declare their own tools: lists — the resolver walks all of them.

Backward Compatibility

The praisonai.* import paths for tool_resolver, _safe_loader, tool_registry, and _framework_availability stay live via identity-preserving sys.modules shims. Each shim does:
This means praisonai.tool_resolver is praisonai_code.tool_resolver — both names point at the same object. The same identity holds for _framework_availability, _safe_loader, and tool_registry, as asserted in test_c5_backward_compat.py::test_module_identity.

Best Practices

Use string names like tools=["internet_search"] rather than inline lambdas. Named tools are resolved through the full 4-tier pipeline, making them easier to override and debug.
Before writing a custom tools.py, check if PraisonAI already has the tool built-in. Run praisonai tools list to see all available built-in tools.
Set PRAISONAI_ALLOW_LOCAL_TOOLS=true only in environments where you trust the local tools.py. This opt-in prevents accidental execution of untrusted code.
The PRAISONAI_ALLOW_LOCAL_TOOLS environment variable must be set to true before Tier 1 (local tools.py) is consulted. This is an opt-in security gate — without it, tools.py is not loaded and the resolver logs why it was skipped (visible at LOGLEVEL=INFO). Only SDK built-ins and plugins are then considered.
When the same name appears in multiple tiers, Tier 1 always wins. If you define def search(...) in tools.py and a plugin also registers search, your local version takes precedence. Use this intentionally to shadow or override built-in tools.
Plugins should register under the praisonai.tool_sources group in their pyproject.toml. This makes them discoverable at Tier 4 without modifying agent code.
Set LOGLEVEL=INFO to see exactly which tier resolved each tool. The log line Resolved 'search' from source 'local-tools.py' confirms which source won.

Configuration Options

Tool Resolver Python Reference

Python reference for the tool resolver module

Project-Local Tools

Drop a Python file in .praisonai/tools/ and praisonai run auto-loads it — zero config.

Local Tools Loading

How to load your own tools.py safely with the PRAISONAI_ALLOW_LOCAL_TOOLS opt-in.

Approval Backends

Choose who approves tool calls — terminal, plan mode, or a chat channel.

Plugins

Register tools and hooks that extend the resolver’s tiers.

Config File

Turn plugins on from [plugins] in config.toml.