Tool API¶
The optional Orchestra Tool submodule (orchestra_tool) connects
Orchestra to Tool API, in both
directions:
- a Tool step runs any Tool API tool as a step of a workflow;
- eight Orchestra tools let any Tool API caller start, follow and correct workflows: an AI agent, an MCP client, ECA, Drush or your own code;
- five more work on a person's own tasks and actions, for an agent with an account of its own: see Agents on human tasks.
Tool API gives a unit of work one typed definition: inputs and outputs, validated before the call, and an access check. The same tool is then callable from everywhere Tool API reaches, and from a workflow.
Drupal 11 only, for now
Tool API declares Drupal 11 at most, so Orchestra Tool does too. Its tests are skipped on Drupal 12 until Tool API supports it.
The Tool step¶
An example¶
An employee submits an expense report, with a photo of the receipt and an
explanation. A step asks a tool to check the receipt. The tool here is one
your site provides, my_module_check_receipt, which prompts an AI model with
a text and an image and answers ok, alcohol or invalid. The flows route
on the answer:
flowchart LR
s([Start]) --> c["Check the receipt<br/>type: tool"]
c -->|verdict == ok| f["Finance review<br/>type: user"]
c -->|verdict != ok| e["Amend the receipt<br/>type: user"]
e --> c
n_check:
type: tool
config:
tool_id: my_module_check_receipt
input: |
receipt_file|image
input_values: |
prompt|Check this receipt. Note: [orchestra:var:receipt_description]
output: |
answer|verdict
run_as: account
run_as_name: finance_robot
payload_variable: check
features:
retry:
max_attempts: 3
backoff: PT1M
on_failure:
policy: outcome
variable: check
receipt_file holds the id of the uploaded file. The step loads the file and
hands it to the tool's image input. finance_robot must be able to read the
expense submissions, so that it may download the receipt. The prompt is a text
with a token in it. After the step, verdict holds the tool's answer, and check holds
success. A model that cannot be reached is tried three times, a minute
apart, and then the step goes on with failed in check.
Settings¶
| Setting | What it does |
|---|---|
tool_id |
The tool to run. The settings form lists every tool of the site, and shows the inputs and outputs of the one picked. |
input |
Variables passed to the tool, one per line. name when the input has the same name, name\|input otherwise. |
input_values |
Inputs given a text, one per line as input\|text. Tokens read the instance and the branch, and are replaced as plain text. |
output |
Outputs written to variables, one per line. name keeps the name, name\|variable renames it. |
run_as |
initiator, the account that started the instance, or account, the one run_as_name names. |
run_as_name |
The user name of the account the tool runs as, with run_as: account. |
payload_variable |
Optional. Set to success when the tool succeeded. |
completion_scope |
instance, or token to keep what the step writes to its branch. |
The settings form refuses an input or an output the tool does not have, an input given two variables or both a variable and a text, a required input the step gives nothing, a payload variable that would replace an output, and a user name that names no active account. A workflow depends on the module that provides its tool: a config import installs that module first, and its uninstall is refused while a workflow runs one of its tools.
Values¶
A variable keeps its JSON type on the way in: a number stays a number, a list
a list. Tool API converts what it can to the type an input declares, so the
text "42" from a token reaches an integer input as 42.
A variable holding an id feeds an input that takes an entity: the step loads the entity of the type the input declares. A list of ids feeds a list of entities. An id that names nothing fails the step, naming the input. So does an entity the account the tool runs as may not view, or a file it may not download: the id may come from whoever could set the variable, such as the person filling a form. A file uploaded with a Webform submission can be downloaded by whoever may read that submission.
A date-time crosses as the moment it names. A variable without an offset
means the site's clock, as everywhere in Orchestra, while Drupal's typed data
means UTC, and Tool API would read it on the clock of the account the tool
runs as, where users may set their own timezone. So the step hands a datetime_iso8601 input the moment written with
the site's offset, and writes a datetime_iso8601 output without an offset, which is
UTC, with +00:00. A Unix timestamp in a variable names its own moment. A
date alone, such as 2026-11-02, is a day rather than a moment, and crosses
as it is.
An entity the tool returns is written as its id, since a variable
holds JSON. A text object, such as a translated message, is written as its
text. Lists and maps are written as they are. An output holding any other
object fails the step. An output the tool leaves out is written as null, so
a step run again in a loop never leaves the previous run's value.
Who the tool runs as¶
An automated step has no current user. The tool runs as the account the step names: its permission and its own access check are asked of that account, and what it does is done by that account.
- With
run_as: initiator, an instance nobody started fails the step. It does not run the tool as anonymous. - With
run_as: account, name an account that holds just what the tool needs.
This differs on purpose from the Action task, which runs its action with full privilege.
Failures¶
A tool that fails fails the step, with the tool's own message:
- A refused input or a denied access fails it at once. Running the tool again would fail the same way.
- Any other failure, such as a service that cannot be reached, is retried by the node's retry policy.
Then the step's "If this step fails" decides, as for any step: an incident, a failed instance, or a failure outcome the flows route.
Slow tools¶
The tool runs inside the advance that reaches the step, as an HTTP request does. A workflow running synchronously runs it inside the request that advanced it: the person who submitted the form waits for the model to answer. Run a workflow calling a slow tool on the queue. An advance must also finish within five minutes, after which the engine lets another worker take the step again.
AI tools and what they are given¶
A prompt built from a form carries whatever the person filling the form typed. They can write instructions in it, or on an uploaded image, and a model may follow them. Wrapping the data in tags, or attaching it as a file, makes that less likely. Nothing makes it impossible.
So design the workflow so it does not matter:
- Let the answer route, not act. In the example, an explanation that
talks the model into answering
oksends the receipt to the finance review it was headed for anyway. - Keep a person, or a strict check, after an AI answer before anything is approved, paid or published.
- Ask for one of a few answers, such as
ok,alcoholorinvalid, and route only on those. A flow for "anything else" catches the rest.
The Orchestra tools¶
| Tool | What it does | Permission |
|---|---|---|
orchestra_list_workflows |
Lists the workflows that can be started, with the variables their instances begin with. | Access Orchestra process instances, or Administer Orchestra |
orchestra_start_workflow |
Starts an instance, with variables, a label, a correlation key and an idempotency key. Returns its id. | Access Orchestra process instances, or Administer Orchestra |
orchestra_get_instance |
Reads an instance, as the operator trace shows it: its state, its status, its open steps, its variables. | Access Orchestra process instances, or Administer Orchestra |
orchestra_view_instance |
Reads an instance the caller started or works on, as its user-facing page shows it: its status, the statuses it has passed through, the steps it waits on, and the data submitted with it. | None beyond the gate, as that page asks none |
orchestra_list_instances |
Lists instances, newest first, of one workflow or in one state, a page at a time. | Access Orchestra process instances, or Administer Orchestra |
orchestra_list_my_requests |
Lists the instances the caller started, newest first, as their My requests page shows them, a page at a time. | View own Orchestra process instances |
orchestra_cancel_instance |
Cancels a running instance. | Access Orchestra process instances, or Administer Orchestra |
orchestra_set_variable |
Sets an instance-wide variable of a running instance. | Administer Orchestra |
Permissions¶
Every Orchestra tool needs two permissions:
- Access Orchestra tools, the gate of every tool;
- the permission the same action needs on the pages of the site, listed in the table above.
So an account uses the tools with the rights it already has on the pages, and only once it is let in. Example: to set a variable through an MCP client, an account needs Access Orchestra tools and Administer Orchestra, as the Edit link of the instance page asks for the latter. An account that only has Access Orchestra tools can run no tool.
Starting is the one exception. The Start link of a workflow page asks for Administer Orchestra, which also lets an account edit every workflow. An agent starting leave requests needs no such right, so listing the workflows and starting one ask for the same permissions as the other instance tools.
An MCP client lists a tool by its declared permission alone. The instance pages let in either of two permissions, which a declared permission cannot say beside the gate. So the five instance tools declare only the gate, and an account with the gate alone sees them listed, but is refused when it runs one.
Access Orchestra tools is restricted, as are Access Orchestra process instances and Administer Orchestra. Access Orchestra process instances lets an account read every instance of the tenant and its variables. Grant them to the account an agent acts as, not to a broad role.
The permissions of the pages are declared by the Orchestra module itself, so they exist on a site running Orchestra Client too. There, the remote Orchestra checks them again. Each instance tool sends the proof of the person running it, and the remote asks that person's own permission, as its instance pages do. A person this site lets use the tools but who may not see instances on the remote reads nothing there, and changes nothing, beyond viewing the instances they belong to. The remote also checks what the site may do, with the permissions of its consumer. Where the remote grants this site no way to prove people (see how the two sites identify the same person), the tools have no proof to send, and the remote checks only the permissions of its consumer.
See Changing a variable for an example.
From Drush, for example:
drush tool:run orchestra_start_workflow --uid=2 \
--input='{"workflow":"leave_request","variables":{"days":3}}'
An AI agent finds the same tools through the Tool AI Connector, and an MCP
client through MCP Server and its Tool Bridge. With the Tool Bridge and MCP
Server OAuth installed, every Orchestra tool comes configured for MCP
clients: listed, and run only with an OAuth token holding the orchestra_mcp
scope, which Orchestra Tool ships too. See MCP clients to let each
person call them with their own account.
The tools go through the Orchestra client, the contract every caller uses. They see what any caller sees: the current tenant's workflows and instances, and nothing of another tenant's. On a site running Orchestra Client, they drive the remote Orchestra.
A single start tool serves every workflow, which it names as an input. A tool per workflow would show every tenant's workflow names to every caller, since tools are the same for the whole site. "List Orchestra workflows" gives a caller the names and variables of its own tenant instead.
An instance a tool starts belongs to the account running the tool. Through a remote Orchestra, that is the person this site can prove there, as for the task tools, and nobody when the remote grants no way to prove one (see how the two sites identify the same person). When the remote cannot place the person, for example because they have no account there, it refuses the start rather than start an instance that belongs to nobody.
What Orchestra refuses, such as an unknown workflow or an instance that is not running, is an input failure: the caller's to fix. A remote Orchestra that does not answer is a runtime failure, so a caller tries again, and a tool step running the tool follows its retry policy. An idempotency key keeps that retry from starting a second instance. A remote Orchestra keeps the key; this site's own engine starts an instance on every ask.
These tools do not complete a person's step. Four other tools work through a person's inbox, listing, reading, claiming and completing tasks: see Agents on human tasks.