Remote Actions
Remote actions let a behavior tree node delegate its work to an external HTTP service — for example a Python process running an LLM tool, or a separate microservice. Orchestration stays in the Rust engine while the actual work happens outside the process.
Scheme
sequenceDiagram
participant BT as Behavior Tree
participant RA as Remote Action (ImplRemote)
participant SVC as External HTTP Service
participant API as Forester HTTP API
BT->>RA: tick
RA->>SVC: POST RemoteActionRequest
SVC->>API: read/write blackboard, record trace (via serv_url)
SVC-->>RA: TickResult (Success / Failure / Running)
RA-->>BT: tick result
- When the tree reaches a remote action, the engine
POSTs aRemoteActionRequestto the action’s configured URL. - The external service performs the work and answers with a
TickResult(Success,Failure, orRunning). - While it runs, the service calls back to the Forester HTTP API at the
serv_urlto read/write the Blackboard and record tracer events.
Request / Response
The engine sends the following request body:
{
"tick": 3,
"args": [
{ "name": "arg", "value": 42 }
],
"serv_url": "http://127.0.0.1:46123"
}
tick— the current tick of the tree.args— the arguments passed to the action from the tree.serv_url— the URL of the Forester HTTP server (see HTTP API).
The remote endpoint answers with a TickResult, one of "Success", "Running", or {"Failure": "reason"}.
Background operations via the generated client
The remote action runs in the background against the Forester HTTP API. Instead of crafting the HTTP calls by hand, use a client generated from the OpenAPI specification (GET /openapi.json). Both Rust and Python ship the same client as forester-client-http, exposing a ForesterClient.
The client takes serv_url from the request and exposes typed helpers for the Blackboard and tracer:
#![allow(unused)]
fn main() {
use forester_client_http::ForesterClient;
let client = ForesterClient::new(&req.serv_url)?;
client.put("key", json!({ "f1": 1 })).await?; // write to the blackboard
client.get("key").await?; // read from the blackboard
client.lock("key").await?; // lock a blackboard entry
client.trace("event", req.tick).await?; // record a tracer event
client.print_trace().await?; // fetch the tracer
}
The Python client mirrors the same API:
from forester_client_http import ForesterClient
client = ForesterClient(serv_url)
client.put("key", {"f1": 1}) # write to the blackboard
client.get("key") # read from the blackboard
client.lock("key") # lock a blackboard entry
client.trace("event", tick) # record a tracer event
client.print_trace() # fetch the tracer
See the HTTP API page for the full list of endpoints and the forester-examples repository for complete Rust and Python implementations.