tools.py, tools/ folder, or explicit --tools /path/to/file.py — after you flip the PRAISONAI_ALLOW_LOCAL_TOOLS=true opt-in.
Quick Start
1
Add a tools.py next to your script
Expose a plain Python function in Then use it from an Run with the opt-in env var:
tools.py:Agent:2
Use an explicit path from the CLI
Pass an absolute path with Explicit user-provided
--tools — useful for tools files outside your project directory:--tools paths bypass the CWD boundary check (allow_outside_cwd=True), so absolute paths outside the repo work under the opt-in flag. CWD-derived tools.py / tools/ scanning stays strict against .. traversal.How It Works
The loader checks two conditions before executing your file:-
PRAISONAI_ALLOW_LOCAL_TOOLSmust be set totrue(case-insensitive). If not, it logs:Refusing to exec {module_path}: set PRAISONAI_ALLOW_LOCAL_TOOLS=true to enable. -
The resolved path must be inside the current working directory (unless you pass an explicit
--toolsargument). If the path escapes the CWD boundary, it logs:Refusing to exec {path}: outside working directory.
--tools file.py also warns via stdout. When you pass a file path to --tools, --rewrite-tools, --expand-tools, or research --tools, the CLI additionally prints a yellow warning to stdout if the load produced zero functions:
Warning: No tools loaded from {path} (module has no public functions, or local tools loading is disabled — set PRAISONAI_ALLOW_LOCAL_TOOLS=true to enable).
The dual-cause phrasing is deliberate (PR #2935) — the same empty result covers both “env-var unset” and “module has no public functions after functions_only=True, skip_private=True filtering”. See Security Environment Variables for the full message table.
Zero-config with .praisonai/tools/
Project-local .praisonai/tools/*.py are auto-loaded on praisonai run without any --tools flag, gated by the same PRAISONAI_ALLOW_LOCAL_TOOLS opt-in. Discovery walks user-global ~/.praisonai/tools/ plus the project walk-up to the git root, and each public function is exposed as <module>.<function>.
@tool vs plain-callable behaviour.
Discovery Order
When you reference a tool by name (e.g.tools=["read_notes"]), PraisonAI checks four places in this fixed order — first match wins:
- Local
tools.py— backward compatibility, custom tools, custom variables praisonaiagents.tools.TOOL_MAPPINGS— built-in SDK toolspraisonai-toolspackage — external tools (optional install)- Tool registry (plugins via
entry_points) — third-party plugin sources
LocalManagedAgent uses this same discovery order for its tools=[...] field. Tool names you drop in tools.py are picked up by both Agent(tools=[...]) and LocalManagedAgent(config=LocalManagedConfig(tools=[...])). See Local Managed Agents.
tools.py vs tools/ Folder
When an explicit tools.py is bound via --tools (or found at the CWD root), it takes priority over a sibling tools/ folder. The resolver honours the bound path, so an explicit --tools tools.py no longer silently loses to a sibling tools/ directory. CWD-derived scans still enforce ..-traversal safety.
--tools Outside Your Project
Only explicit user-provided paths — those you pass via --tools /path/to/file.py — opt out of the CWD boundary check. Anything the framework derives (recipe metadata, API-supplied names) stays strict. From the _safe_loader docstring:
“When True, skip the CWD boundary check. Only pass this for paths the user provided explicitly (e.g. a --tools CLI argument), never for API/network-derived paths.”
Best Practices
Keep tools.py at the top of your project
Keep tools.py at the top of your project
Keep
tools.py at the top of your project — the CWD boundary check will find it without any flag.Only set the env var in trusted shells
Only set the env var in trusted shells
Only set
PRAISONAI_ALLOW_LOCAL_TOOLS=true in trusted shells; a bare pip install will execute the file you point at.Use absolute paths for tools outside your project
Use absolute paths for tools outside your project
For absolute paths outside your project, pass the full path via
--tools — the resolver will honour it under the opt-in flag.Related
Project-Local Tools
Drop a Python file in .praisonai/tools/ and praisonai run auto-loads it — zero config.
Tool Discovery Order
The 4-tier pipeline that resolves tool names — local file, built-ins, praisonai-tools, or a plugin.
Approval Backends
Choose who approves a tool call — terminal prompt, plan mode, or a chat channel.

