Learn how to create custom Invoker scripts to extend SIERRA's functionality and automate your investigation workflows.
Invoker scripts let you run any external tool or script — in any language — directly from the SIERRA canvas. Define them in simple YAML, then run them from your investigation graph to automate tasks, call APIs, and capture results back into the graph for immediate analysis.
Copy a ready-made Markdown prompt for ChatGPT, Claude, or any other model. It includes the valid SIERRA schema, V1/V2 output rules, and the response format we want back.
After pasting it into the model, replace the finalUser Requestsection with your workflow.
An Invoker script is defined by a YAML configuration file, which tells SIERRA how to present parameters, run your command, and handle its output in the graph. It has the following structure:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# [Optional]: Working directories SIERRA will try as cwd when executing Command
# These entries are not executable search roots
PATHS:
- /path/to/script/directory
- /another/path
# [Mandatory]: Contains the list of Invoker scripts
SCRIPTS:
- Name: Unique Script Name # [Mandatory]
Description: Brief description of the script
Protocol: V2 # [Optional] omit for V1 batch invokers
Params: # [Mandatory]
- Name: ParameterName # [Mandatory]
Description: Parameter description # [Optional]
# [Mandatory]: The data type of the parameter
# Supported types: STRING, FILE
Type: STRING
Options: # [Optional]
- MANDATORY # indicates this parameter cannot be empty
Command: command_to_execute {ParameterName} # [Mandatory]PATHSonly controls the working directory SIERRA uses while running your command. It does not tell SIERRA where to discover executables. Use full commands or rely on the runtime PATH available in that working directory.SIERRA currently supports two invoker output contracts:V1 for batch/final JSON, and V2 for incremental node emission.
V2support when talking to SIERRA Cloud, so cloud-only streaming invokers can be hidden from legacy clients.V1: The command finishes first, then stdout is parsed once as a finalTree,Network, orErrorobject.
V2: The command writes one JSON object per line to stdout while it runs.resultevents create nodes immediately,progressupdates the invoker UI, andendcloses the stream.
For the default V1 contract, your script should return JSON in one of these supported formats:
The type field should be Tree. Perfect for hierarchical data structures.
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"type": "Tree",
"results": [
"Content of Entity A",
"Content of Entity B",
{
"Content of Entity C (parent of D and E)": [
"Content of Entity D",
"Content of Entity E"
]
}
]
}The type field should be Network. Ideal for complex relationship mapping.
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"type": "Network",
"origins": ["AliceID"],
"nodes": [
{ "id": "AliceID", "content": "Alice" },
{ "id": "BobID", "content": "Bob" },
{ "id": "CharlieID", "content": "Charlie" }
],
"edges": [
{ "source": "AliceID", "target": "BobID", "label": "friend" },
{ "source": "AliceID", "target": "CharlieID", "label": "colleague" }
]
}When your script encounters an error, return a JSON object with type: "Error".
1
2
3
4
5
6
7
8
9
10
11
// Service error
{
"type": "Error",
"message": "API connection failed"
}
// Input validation error
{
"type": "Error",
"message": "Invalid email format"
}Use Protocol: V2 when your local invoker benefits from incremental results, such as search, scraping, enumeration, or long-running collection jobs.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
PATHS:
- /opt/scripts
SCRIPTS:
- Name: Username Search
Description: Emits usernames as they are found
Protocol: V2
Params:
- Name: Username
Description: Username to search
Type: STRING
Options:
- MANDATORY
Command: python username_search.py "{Username}"Your script should write one compact JSON object per line tostdout. Do not pretty-print multi-line JSON.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import json
def emit(event):
print(json.dumps(event), flush=True)
username = "alice"
emit({
"version": 2,
"type": "progress",
"message": f"Searching for {username}"
})
emit({
"version": 2,
"type": "result",
"id": "root",
"content": f"# Username Search\n{username}"
})
emit({
"version": 2,
"type": "result",
"id": "github",
"parent": "root",
"content": "# GitHub\nhttps://github.com/alice"
})
emit({
"version": 2,
"type": "end",
"summary": "1 account found"
})Recommended event types: result,progress,end, anderror.
Parenting: omit parent to attach directly to the invoker node, or reference a previously emitted result id.
Logging: keep protocol events on stdout; send ordinary debug logs to stderr.
Here's a complete example of an Invoker script configuration for a subdomain lookup utility:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PATHS:
- /opt/scripts
- /home/user/tools
SCRIPTS:
- Name: Subdomain Finder
Description: Looks up subdomains of a given domain using crt.sh
Params:
- Name: Domain
Description: The domain to find subdomains for
Type: STRING
Options:
- PRIMARY
- MANDATORY
Command: python subfinder.py {Domain}Follow these guidelines for optimal Invoker script development:
•
Validate inputs: Always validate parameters before processing
•
Handle errors gracefully: Return meaningful error messages
•
Use descriptive names: Make script and parameter names self-explanatory
•
Test thoroughly: Verify output formats work correctly in SIERRA
•
Document your scripts: Include helpful descriptions and examples
Start building Invokers to supercharge your investigations, from quick lookups to complex multi-step automations.
OSINT tools for modern investigators and security professionals.
© 2026 Phantom Helix Intelligence. All rights reserved.
Made with ❤️ for the OSINT community