The
composio: prefix only tells you where a discovered tool came from. Every kind goes through the same execution path, which means authorization-on-demand, retries, and dry-run stubbing behave the same whichever you use.
Curated tools
Four toolkits have hand-written tools with argument names px0 controls:
These exist because a handful of actions come up in almost every workflow, and a stable argument name (
url, channel, text) is easier to hand-write than Composio’s generated schema. They are a convenience, not a limit.
Discovered tools
Anything in Composio’s catalogue - thousands of tools across hundreds of toolkits - is reachable. You do not look them up yourself:px0 workflows new writes searches (a toolkit plus a capability phrase), Composio returns candidates, and the model picks from what actually came back. Nothing is invented, because a slug that does not appear in the results is discarded.
Once a workflow uses a discovered tool, it is recorded in your store. That has two useful consequences: the tool shows up in px0 tools list alongside the curated ones, and the workflow keeps resolving it without another catalogue lookup - so a workflow written today still runs offline tomorrow.
Local tools
Beyond the apps Composio brokers, a workflow can use what is already on this machine:shell.run is listed by px0 tools list even when disabled, so it is discoverable, but it refuses to run until you turn it on - a workflow that can run a shell can do anything you can.
Tools you declare yourself
Anything else you want a workflow to do, declare it in one TOML file per tool under the store’stools/ folder:
px0 tools list immediately, and px0 workflows new can use it. Arguments are substituted into argv, never into a shell, so a value with a semicolon in it stays a value. A malformed file in tools/ is reported as a warning and skipped, so one bad declaration never hides the rest.
Read, write, and destructive
Every tool declares its access, and px0 takes that from Composio’s own metadata rather than guessing from the name:
This one distinction shapes a lot of px0’s behaviour, because it is the difference between a workflow that wastes your time and a workflow that embarrasses you in a public channel:
- The builder calls out write tools before generating a workflow, and lets you drop any you did not ask for.
- Validation rejects a write tool in
inputs, since inputs run unconditionally. --dry-runstubs write tools instead of executing them, so you see what would have been posted.px0 runsmarks any run that called one with[write].
Inspect what is available
read / write marker is the only thing on that screen px0 bothers to colour, because it is the only thing that can surprise you.
--status costs one API call per toolkit, which is why it is opt-in rather than always on. The statuses themselves are explained in Connections.
Parameter schemas
When you are writing a workflow’sargs by hand, you want the actual schema:
* and listed first, so the shape of a call is obvious at a glance.
Search Composio’s catalogue directly
px0 workflows new, which is the only other thing that searches the catalogue. Results are marked read, write, or destroy, from Composio’s own hints.
Call one tool directly
--arg key=value is repeatable; a value that parses as JSON is sent as JSON, so --arg labels='["bug"]' sends a list. A write tool asks to confirm first, unless --yes is given.
Refresh cached definitions
--forget drops the cache instead of re-reading it.
Use a tool in a workflow
Nothing special is required - name it in the frontmatter and the runner takes care of both authorization and, if needed, asking you to authorize:tools: list are callable by the model during the run. Full field reference: Workflow files.
When a tool call fails
Every tool call is recorded with its own timing in the run record, so a slow run tells you exactly which connector was slow. See Browse runs.

