.praisonai/agents/, .praisonai/commands/, and .praisonai/tools/ to extend the CLI without writing packaging code. Existing .claude/agents/, .claude/commands/, .agents/agents/, and .agents/commands/ layouts from other agent tools are picked up too — no migration required.
The user runs praisonai run --agent researcher; discovery loads custom agents, slash commands, and project-local tools from .praisonai/.
How It Works
Quick Start
Skip the boilerplate —
praisonai init scaffolds a working .praisonai/ with a starter agent and command, then read on to customise.1
Create an agent file
2
Run the agent
3
Create a command file
4
Run the command
How discovery works
Agents and commands are discovered from.praisonai/ and the conventional ecosystem roots .claude/ and .agents/. Tools stay .praisonai-only because loading them executes user code.
Precedence (later wins on name collision):
- Nearer directory beats a more distant ancestor — a nested package’s definition overrides one inherited from a parent repo.
- Within the same directory level,
.praisonai/beats.claude/and.agents/— project-native definitions win over imported ones. - User-global (
~/.praisonai/) is overridden by any project-level match.
Reusing existing .claude/ or .agents/ layouts
Already have agents defined for another tool? PraisonAI picks them up as-is:
.praisonai/agents/reviewer.md, that project-native file wins.
Agent definitions
Files:.praisonai/agents/*.md|*.yaml, .claude/agents/*.md|*.yaml, .agents/agents/*.md|*.yaml
Tool composition on praisonai run --agent
When praisonai run --agent <name> runs, the agent’s tool list is built from these sources, in order, and dedup’d by callable identity:
Example:
--agent path.
Scoping permissions
Three built-in agents (
build, plan, review) are available without any file — see Agent Presets & Modes.mode: to a definition for instant read-only or review scoping:
permission: block:
Supported mode: values
mode: subagent marks an agent as delegatable from other agents at run time (see Named Agent Delegation). It is a marker only — it does not apply any permission changes and is ignored when computing permissions. Every other mode: value still flows through the permission engine as before.
Command templates
Files:.praisonai/commands/*.md, .claude/commands/*.md, .agents/commands/*.md
Positional arguments
Reference$1, $2, …, $n to pull individual tokens out of the user’s argument string — $ARGUMENTS still holds the whole string.
Command frontmatter
Frontmatter fields tune how a command runs. Every field is optional — a command with only adescription still works.
tools wins when present; otherwise allowed-tools / allowed_tools supply the list.
tools is equivalent to the YAML list above:
Opt-in live shell substitution
!`cmd` is disabled by default. Enable with any one of:
PRAISONAI_ALLOW_SHELL=trueenvironment variablecommands.allow_shell: truein.praisonai/config.yaml- Per-command frontmatter
allow_shell: true
ShellSubstitutionError. !`cmd` inside $ARGUMENTS or @file contents is never executed — only markers in the original template run.
The same gate now controls the interactive
!cmd shell escape in praisonai code. Enabling PRAISONAI_ALLOW_SHELL=true (or commands.allow_shell: true) turns on both !`cmd` template substitution and the interactive ! / !! prefixes. See Shell Escape for the interactive surface.Project-local tools
Drop any.py file into .praisonai/tools/ and every praisonai run — including run --agent <name> — in that project auto-loads its tools — no --tools flag, no packaging, no imports in your agent code.
Only .praisonai/tools/*.py is auto-loaded. .claude/tools/ and .agents/tools/ are intentionally ignored, because loading a tool executes Python — this keeps a drop-in ecosystem checkout from running arbitrary code.
How discovery works
What gets loaded
Precedence & opt-out
A richer example — private helpers stay private
Scaffold a single agent with praisonai agent create
Turn a one-line description into a permission-scoped agent file in one command — no editor round-trip.
read-only / review / full) maps to the same mode: shorthand documented in Scoping permissions above — no parallel grammar. When a provider credential is available, the system prompt is drafted via the LLM; otherwise the CLI writes an editable stub so file creation never blocks.
Use this when you want one focused agent; use praisonai init when you also want starter commands and a tools scaffold next to it.
See praisonai agent create for the full flag reference.
Scaffold with praisonai init
example.py is a commented @tool stub — uncomment or replace it in place. For a single-agent scaffold, see praisonai agent create.
Making an agent delegatable
Mark an agent withmode: subagent so a running primary agent can hand it sub-tasks by name.
praisonai run --agent lead) can call spawn_subagent(agent_name="researcher", …) and this agent runs the sub-task under its own model/tools/permissions. See Named Agent Delegation.
Agent vs command vs skill vs rule
Slash commands
Custom commands auto-register in interactive mode asCommandKind.CUSTOM. Disable with SlashCommandHandler(discover_custom=False).
Custom commands appear automatically in Telegram / Discord / autocomplete when your bot restarts, filtered by the same CommandAccessPolicy that gates execution. See Native / Autocomplete.
The same
.praisonai/commands/{name}.md file now also runs in bot chats (Telegram / Slack / Discord), not just the code REPL/TUI. Enable it per channel with a commands block (opt-in via bots.commands) — one file, two surfaces, no duplication. Shell (!`cmd`) substitution stays off in bots unless both the deployment and the command’s frontmatter opt in. See File-based & Entry-point Commands in Bot Chats.Inside praisonai code too
The same .praisonai/commands/*.md files work as /name inside praisonai code, the REPL, and the async TUI. A unified CommandRegistry aggregates built-ins, your custom commands, skills, MCP prompts, and pip-installed praisonai.commands packs into one namespace:
praisonai run --command mydeploy staging would — byte-for-byte parity between interactive and CLI. See Slash Commands → Unified Command Registry.
Python API
discover_project_tools() returns a list of tool callables (empty unless PRAISONAI_ALLOW_LOCAL_TOOLS=true). For metadata, CustomDefinitionsDiscovery().list_tools() returns CustomTool(name, path, callable, source) records where name is the namespaced <module>.<func>.
Best Practices
Use project files for team sharing
Use project files for team sharing
Commit
.praisonai/agents/, .praisonai/commands/, and .praisonai/tools/ to git. Every teammate and CI run picks up the same tool set on the next praisonai run — no pip install and no --tools flag.Decorate public tools, keep helpers private
Decorate public tools, keep helpers private
.praisonai/tools/_helpers.py is skipped entirely. Inside a loaded file, functions without @tool are only fallback-loaded when the file has no @tool at all — so decorating your public entry points keeps private helpers off the LLM’s tool list.Keep user-global files personal
Keep user-global files personal
Use
~/.praisonai/ for personal shortcuts that should not override team agents.Keep project-native definitions in .praisonai/
Keep project-native definitions in .praisonai/
Keep team-owned, project-native definitions in
.praisonai/ — they win on name collision and are the single source PraisonAI writes to (e.g. praisonai init, praisonai agent create). Point PraisonAI at your existing .claude/agents/ or .agents/commands/ when you want to reuse assets that already ship in your repo for another agent tool, without duplicating them.Never rely on unguarded shell substitution
Never rely on unguarded shell substitution
!`cmd` requires an explicit opt-in gate (allow_shell: true, config, or PRAISONAI_ALLOW_SHELL). $(...) is always escaped — use !`cmd` only when you need live output like git diff.Prefer $1..$n when the order matters
Prefer $1..$n when the order matters
Positional args make the interpolation explicit and let you write help hints (
argument-hint: <from> <to>) that survive editor tooltips. Use $ARGUMENTS only when the command should receive the raw request verbatim.Set argument-hint for every non-trivial command
Set argument-hint for every non-trivial command
The hint shows up when the command is listed in
praisonai command list / autocompleted in the interactive REPL and in bot slash-command menus. It’s the fastest way to teach yourself and your team what an argument looks like without opening the file.Use tools: to sandbox the command
Use tools: to sandbox the command
When set, the command runs with only those tools available even if the caller’s default agent has more. Pair with a read-only
model: for review/inspection commands.Start with praisonai init
Start with praisonai init
Run
praisonai init to scaffold .praisonai/agents/, .praisonai/commands/, and .praisonai/tools/ before hand-writing files.Related
Run CLI
—agent and —command flags
Agent CLI
List and inspect custom agents
Command CLI
List and preview commands
Slash Commands
Interactive custom commands
Init CLI
Scaffold .praisonai/ in one command
Tools
The @tool decorator and building custom tools
Project-Local Tools
Auto-discovered .praisonai/tools/*.py on run and run —agent
Agent Presets & Modes
Built-in presets and per-agent permission scoping
Named Agent Delegation
Delegate named sub-tasks to your agents with mode: subagent

