Adding a New WF_Agent Webhook to Kilroy AI Services
This tutorial explains how to add a new wf_agent type to Kilroy's AI pipeline system. A wf_agent is a
pipeline node that appears in the pipeline editor palette and, when it receives a swarm message, calls a
server-side webhook to process the message and optionally publish a result back to the pipeline.
Adding a new wf_agent requires coordinated changes in three places:
- The pipeline editor palette — defines how the new agent appears in the editor and its default configuration
- The webhooks process diagram — registers the webhook trigger endpoint
- The workflow — implements the actual processing logic in JavaScript and workflow JSON
Overview: How wf_agents Work
When a wf_agent receives a message on its input swarm, the Kilroy runtime optionally calls a webhook on the
kilroy.ai.webhooks process diagram. The webhook trigger maps to a workflow, which runs on the backend. The
workflow's preflight function in script.js processes the incoming message, and the result is passed back
to the pipeline as a new swarm message published to the agent's output swarm (when wf_publish_results is true).
The incoming message data is available to the workflow in the webhook_args global context variable, which
contains the following standard fields:
| Field | Description |
|---|---|
tagentname |
The name of the sending agent |
tusername |
The username associated with the message |
tid |
The message transaction ID |
tpublish |
Whether to publish the result (boolean/string) |
targs |
JSON string of per-instance configuration args from the node's wf_webhook_args |
args |
Array of message objects; each has text, type, and timestamp |
from |
Agent/user the message originated from |
The workflow builds a resp object containing the result and sets it in global context. A block in the
workflow's step_group assigns resp to x, which the runtime uses as the payload to publish back to the
outbound swarm.
Step 1: Create the Workflow
Workflows live under:
Each workflow folder contains exactly three files:
| File | Purpose |
|---|---|
script.js |
JavaScript preflight/postflight logic |
json.json |
Compiled workflow definition (executed by the workflow engine) |
xml.xml |
Blockly source representation (used by the visual workflow editor) |
1a. script.js
Start by copying the template from:
Replace all ${_rebar_wfName} occurrences with your workflow's full name
(e.g., kilroy.ai.services/webhooks/add_1) and update the @author and @copyright fields.
The preflight function is where your logic lives. Use wfProxy.getGlobalValue("webhook_args") to access
incoming message data, do your processing, build the standard resp object, then call
wfProxy.setGlobalValue to pass values to the workflow blocks.
A minimal preflight that transforms message text looks like this:
Note
The only functions available on wfProxy are those exported by
api/modules/wf/workflow_proxy.js. There is no getWebhookArg shortcut —
always use getGlobalValue("webhook_args") and extract fields from the returned object.
1b. json.json
Start from the template at api/platform_data/demo/templates/WORKFLOW_KIND/payload/json.json and replace
${_rebar_wfName}. For a standard publish-result webhook, the structure is:
Key points:
isInteractivemust befalsefor a webhook — it runs entirely on the backend with no user interaction.canTerminatemust befalsefor the same reason.outputs: ["tpublish"]causes thetpublishvariable (set in preflight) to be persisted in the workflow instance record.- The single block in
step_group.successassigns therespobject (set in preflight) to the context variablex, which the runtime uses as the outbound message payload. - If
script.jshandles all logic and only sets__results__, thesuccessarray can be empty andoutputscan be[].
Warning
isServer: true on a block means the block runs on the backend. Set it to false only for blocks
that require frontend interaction (e.g., showing a form). All webhook workflow blocks should be
isServer: true.
1c. xml.xml
The xml.xml file is the Blockly visual-editor source. For a simple webhook that is maintained
programmatically rather than via the Blockly editor, this file documents the intended structure but is
not directly executed. It should match the block structure in json.json. Copy and adapt the XML from
a similar existing webhook in workflows/webhooks/.
Step 2: Register the Webhook in the Process Diagram
Edit:
Add a new node object to the nodeDataArray. Use a unique negative integer key that is not already in use.
Set loc to a position near other webhook nodes (the canvas uses "x y" string coordinates):
Note
trigger_name must exactly match the webhook name used in wf_diagram_webhook in the palette entry
and in the workflow's name field (the last path segment).
Step 3: Add the Palette Entry
Edit:
Add a new entry to the wf_palette array. The wf_diagram_alias is always kilroy.ai.webhooks (the
runtime alias of the webhooks process diagram, not its template name):
Key palette fields:
| Field | Description |
|---|---|
wf_diagram_alias |
Always kilroy.ai.webhooks for webhook-backed agents |
wf_diagram_webhook |
The webhook trigger_name to call when a message arrives |
wf_call_webhook |
Set to true to invoke the webhook on each received message |
wf_publish_results |
Set to true to automatically publish the workflow result to the output swarm |
wf_webhook_args |
JSON string of default per-instance configuration; users can edit this in the pipeline editor |
agent_is_controller |
true if this agent controls another agent rather than processing data |
agent_is_controlled |
true if this agent can be controlled by a controller agent |
Step 4: Reload and Test
After making these three changes:
- Restart the Kilroy backend (or hot-reload if supported) so the new workflow is picked up.
- Open the pipeline editor in the Kilroy UI.
- The new agent should appear in the
wf_palettesection of the palette. - Drag it into a pipeline, connect it to a swarm, and run the pipeline to test it.
Summary Checklist
- [ ]
workflows/webhooks/<name>/payload/script.js— preflight logic readswebhook_args, buildsresp, setstpublishandrespviasetGlobalValue - [ ]
workflows/webhooks/<name>/payload/json.json— non-interactive,outputs: ["tpublish"], step assignsresptox - [ ]
workflows/webhooks/<name>/payload/xml.xml— Blockly source matching json.json - [ ]
process_diagrams/webhooks/diagram.json— new webhook node with matchingtrigger_nameand uniquekey - [ ]
public/pipeline_editor/js/palette_defs.js— newwf_agententry inwf_palettewith correctwf_diagram_aliasandwf_diagram_webhook