Built-in skills reference
At a glance
- What — the seven skills shipped with the engine. Attach one to a node (
skill=<route>) to make it active: it runs when traversal reaches the node.- They share — Event Script data-mapping syntax (
source -> target) and the same state-machine namespaces (input.*,model.*,output.*,{node}.result).- One skill per node. A node returns a decision to the engine —
next(follow the connection), a node name (jump), or.sink(pause this path).
| Skill | Use it to… |
|---|---|
graph.data.mapper |
copy/transform data between namespaces |
graph.math |
compute and branch with fast inline math/boolean |
graph.js |
compute/branch with full JavaScript (slower) |
graph.api.fetcher |
call external HTTP APIs declaratively |
graph.extension |
delegate to a sub-graph or an Event Script flow |
graph.join |
synchronize parallel paths |
graph.island |
mark an isolated/organizational node |
graph.data.mapper
Copies and transforms data between state-machine namespaces. The workhorse for shaping inputs and building the response.
skill=graph.data.mapper
mapping[]=source -> target
Sources/targets use input.*, model.*, output.*, or a node name (its properties); text(...),
int(...) etc. inject constants. Example:
create node my-mapper
with properties
skill=graph.data.mapper
mapping[]=input.body.hr_id -> employee.id
mapping[]=input.body.join_date -> employee.join_date
graph.math
Fast inline math and boolean evaluation for computation and decision-making. Prefer this over
graph.js when you only need simple expressions. Statements run in order; five types:
| Statement | Purpose |
|---|---|
COMPUTE |
evaluate a math expression → the node's result |
IF |
boolean decision → jump to a node (THEN/ELSE) |
MAPPING |
data-map source → target (no curly braces) |
EXECUTE |
run another graph.math node |
RESET |
clear a node's "seen" flag so it can run again |
skill=graph.math
statement[]=COMPUTE: amount -> (1 - {input.body.discount}) * {book.price}
statement[]='''
IF: (1 - {input.body.discount}) * {book.price} > 5000
THEN: high-price
ELSE: low-price
'''
{variable} resolves a value from input.*, model.*, or a node property into the expression.
An IF returning a node name overrides natural traversal; returning next keeps it. Optional
for_each[] iterates a statement block; NEXT:/DELAY: control flow and timing.
Gotchas: a node runs once (guard against loops) unless you RESET it — an advanced,
use-with-care feature; a node may not contain only MAPPING statements (use the data mapper).
graph.js
Same statement model as graph.math, but expressions run as full JavaScript on GraalVM —
more flexible, slower.
skill=graph.js
statement[]=COMPUTE: amount -> (1 - {input.body.discount}) * {book.price}
Gotchas: capped at 50 instances per deployment (it uses kernel threads); reach for
graph.math unless you need real JavaScript.
graph.api.fetcher
Calls external HTTP APIs declaratively, driven by data-dictionary and provider nodes. Supports response caching and bounded fork-join concurrency.
skill=graph.api.fetcher
dictionary[]=<data-dictionary-node> # one or more
input[]=input.body.person_id -> person_id
output[]=result.name -> output.body.name
for_each[]=<array> -> model.<var> # optional: iterate
concurrency=3 # optional: 1–30, default 3
exception=<error-handler-node> # optional
Worked example (fetch a person's name and address):
create node fetcher
with type Fetcher
with properties
skill=graph.api.fetcher
dictionary[]=person-name
dictionary[]=person-address
input[]=input.body.person_id -> person_id
output[]=result.name -> output.body.name
output[]=result.address -> output.body.address
The result lands at {node}.result. Gotcha: identical requests (same URL + method + input) are
deduplicated into a single HTTP call. See Composing the layers
for the dictionary/provider setup this skill depends on.
graph.extension
Delegates to another graph model or an Event Script flow, so you can compose larger capabilities and reuse logic.
skill=graph.extension
extension=<graph-id> # a sub-graph …
extension=flow://<flow-id> # … or an Event Script flow (note the flow:// prefix)
input[]=input.body.person_id -> person_id
output[]=result -> output.body
Sub-graph example (reuse a deployed graph):
create node performance-evaluator
with type Extension
with properties
skill=graph.extension
extension=evaluate-sales-performance
input[]=input.body.department_id -> id
output[]=result.sales_performance -> output.body.sales_performance
This is the seam between the semantic layer and the composable layer beneath it — see Composing the layers.
graph.join
A synchronization barrier for parallel branches. It returns next only when all connected
upstream nodes have completed, and .sink (pause) until then.
skill=graph.join
connect fetch-name to join with done
connect fetch-address to join with done
connect join to combine with proceed
Gotchas: needs at least two predecessors to be meaningful; it is the explicit fork-join mechanism — without it, traversal proceeds as branches complete.
graph.island
Marks an isolated node: it always returns .sink, so traversal does not continue through it.
Used to organize non-executable configuration (e.g. grouping data-dictionary and provider nodes)
or to park a sub-graph that isn't wired in yet.
skill=graph.island
connect root to dictionary with contains
connect dictionary to person-name with data
connect dictionary to person-address with data
See also
- Build your first Active Knowledge Graph —
graph.data.mapperin a full walkthrough. - Composing the layers — the data-dictionary/provider model for
graph.api.fetcher, andgraph.extensioninto flows. - Event Script Syntax — the shared data-mapping syntax.