Skip to main content
One command installs a tool package and tells you exactly which tools became available β€” or exits non-zero if none did. Previously a package could pip install cleanly yet expose no resolvable tools β€” a silent failure. tools add turns that into a surfaced non-zero exit.

Quick Start

1

Install a tool package

praisonai-my-tools is a placeholder β€” replace it with a real pip requirement spec.
2

Upgrade an installed package

3

Verify without installing

--dry-run skips installation and reports whether any new tool would resolve from what’s already installed.
Enable code execution during install first. praisonai tools add refuses to install a tool package when the source is a local file path, a github: reference, or a bare package name unless PRAISONAI_ALLOW_LOCAL_TOOLS=true is set. All three branches run user code β€” a local file executes on load, a github: fetch downloads then loads, and a bare package name is resolved on sys.path and its __init__ runs at import time. The gate is the same one that governs tools.py autoload (see Security Environment Variables). A published pip install-style spec that is already installed and is only being resolved by name goes through the same import, so the gate applies there too.
On refusal of a bare package name, the CLI prints:
and returns {"success": False, "error": "PRAISONAI_ALLOW_LOCAL_TOOLS not set"}.

How It Works

The command snapshots resolvable tools, installs, builds a fresh resolver, then reports the diff.
Discovery constructs a fresh ToolResolver(). Calling resolver.invalidate() alone is not enough β€” it only clears the per-name resolution cache, not instance-level availability caches (like whether praisonai_tools is importable). A new instance re-evaluates those against the now-updated environment.

Security

  • No code execution for the github: inspection path. The github: download inspects a candidate tools.py with ast.parse β€” it does not execute that downloaded file. But the fetch itself and the load run under the same opt-in.
  • Package-name branch executes __init__ on resolve. praisonai tools add <name> when <name> is neither a local path nor a github: reference calls importlib.import_module(<name>) to inspect the package. That runs its top-level code β€” which is exactly why it is now gated behind PRAISONAI_ALLOW_LOCAL_TOOLS=true.
  • github: downloads are locked down: HTTPS raw URLs only (raw.githubusercontent.com / raw.github.com), no redirect follow, a 1 MiB size cap, and the on-disk filename is derived from the URL’s last path segment as a safe single basename (no directory traversal).
  • No --sha256 flag β€” the PR that hardened this path deliberately left it out to avoid a new CLI knob. Rely on PyPI signing or your own out-of-band verification if you need a pinned artefact.

Options


How the Installer Is Chosen

Installation is pinned to the interpreter running the CLI so the package lands where discovery will look. See plugins add β†’ How the Installer Is Chosen for the shared decision diagram β€” both commands use the same _resolve_installer() logic.

Exit Codes


Output Shape

A successful run prints a Rich table titled Registered N tool(s) from <package>, with the tool’s resolution source:
Source values come from ToolResolver.list_available_sources() and are one of: On --dry-run the title verb is Discovered instead of Registered.

Common Patterns

When uv is present, the package is pinned to the CLI interpreter so a fresh resolver sees it.

Best Practices

If you script installs yourself, build a new ToolResolver() after installing β€” invalidate() clears only the per-name cache, not instance-level availability caches.
A package can install cleanly yet expose no tools. --dry-run exits non-zero when discovery finds nothing new.
The default pins to the CLI interpreter so the tools are resolvable by the same process. Reach for --global only when you want the system environment.
Run praisonai tools list to see every resolvable tool and its source, not just what this command added.

plugins add

Install a plugin package and verify it registered

Tool Source Registry

Plug third-party tool sources via entry points

Tool Resolver

Single source of truth for loading tools

Tool Discovery Order

How Agent resolves tool names at runtime