Custom Content Deployment
This page describes how to deploy custom Modules, Playbooks, SIEM YAML, and Python dependencies to a Docker Compose installation. Complete Deployment first.
1. Custom directory
The Compose deployment mounts the host custom/ directory into backend containers:
| Path | Purpose |
|---|---|
custom/modules/*.py | Custom Modules. |
custom/playbooks/*.py | Custom Playbooks. |
custom/data/modules/<module_slug>/raw_alert_*.json | Module development samples. |
custom/data/siem/*.yaml | Custom SIEM YAML. |
custom/data/playbooks/<playbook_slug>/*.md | Custom Playbook prompts. |
custom/requirements.txt | Extra Python packages required by Modules, Playbooks, or shared helpers. |
init.sh creates the empty directory structure and custom/requirements.txt template. Source examples under backend/custom/ are development references and are not included in release packages.
2. Install Python dependencies
Add dependencies to:
custom/requirements.txtInstall them:
docker compose run --rm asp-custom-depsDependencies are installed at /opt/asp/custom-packages, persisted in the custom-python-packages Docker named volume, and mounted into all backend services.
To choose a Python package index:
docker compose run --rm asp-custom-deps --index-url https://pypi.org/simpleArguments after the service name are passed to uv pip install, for example:
--extra-index-url https://packages.example.com/simple--upgrade
To pass proxy settings into the container:
docker compose run --rm \
-e HTTP_PROXY=http://proxy.example:8080 \
-e HTTPS_PROXY=http://proxy.example:8080 \
asp-custom-deps3. Manage custom variables
Admins can manage variables used by custom Modules and Playbooks under Custom > Variables. Keys may contain only uppercase letters, numbers, and underscores, and cannot be renamed after creation.
Every variable requires a Type:
| Type | Python return type | Value editor |
|---|---|---|
| String | str | Text input |
| Integer | int | Integer input |
| Float | float | Number input |
| Boolean | bool | Switch |
| List | list | JSON code editor |
| Dictionary | dict | JSON code editor |
List and Dictionary support nested JSON values. The editor provides line numbers, syntax highlighting, bracket matching, code folding, and Format; JSON syntax and the top-level type are validated when you save. Dictionary key order is not guaranteed. Use a List when order matters.
String cannot be empty. Integer must be a JavaScript safe integer, and Float must be finite. Boolean false, numeric 0, an empty List, and an empty Dictionary are all valid values. A Value may contain up to 65,536 UTF-8 bytes, and List and Dictionary may be nested up to 20 levels.
Only String can be marked as Secret. Secret values are hidden from normal Admin API responses and edit forms; an Admin must use Reveal to view one. To change a Secret to another Type, disable Secret and enter a new Value. Changing the Type of any variable clears the previous Value and requires confirmation.
Read variables through the base class in custom code:
class Playbook(BasePlaybook):
def run(self):
base_url = self.get_variable("EDR_BASE_URL")
token = self.get_variable("EDR_API_TOKEN")
verify_tls = self.get_variable("EDR_VERIFY_TLS")
headers = self.get_variable("EDR_HEADERS")
if base_url is None or token is None:
raise ValueError("EDR custom variables are not configured.")
if verify_tls is None:
verify_tls = True
if headers is None:
headers = {}BaseModule uses the same lookup method:
class Module(BaseModule):
NAME = "EDR alert processor"
STREAM_NAME = "EDR-Alerts"
def run(self, message):
base_url = self.get_variable("EDR_BASE_URL")
token = self.get_variable("EDR_API_TOKEN")
if base_url is None or token is None:
raise ValueError("EDR custom variables are not configured.")
# Process the alert using message, base_url, and token.BasePlaybook.get_variable() and BaseModule.get_variable() query the current database value on every call and return the native Python type selected by Type. Custom code does not need to parse JSON. They return None when a variable is missing, disabled, or deleted.
Use is None to detect a missing variable
false, 0, [], and {} are valid values. Use value is None to detect a missing variable instead of if not value.
Secrets are not encrypted at rest
The Secret flag only hides a value from normal Admin API responses and lists. The value remains plaintext in the database and can be read by database administrators or anyone with a database backup. Install only trusted custom code, and never write secrets to logs, task summaries, Enrichments, or exceptions.
4. Apply changes
For Module, Playbook, or SIEM YAML changes, use Refresh / Validate in the corresponding Custom Console tab.
After dependency or shared helper changes:
docker compose run --rm asp-custom-deps
docker compose restart asp-web asp-worker-module asp-worker-playbook
./scripts/doctor.sh5. Compose overrides
init.sh creates compose.override.yaml when it does not exist. Docker Compose merges it with the official compose.yaml.
- Keep supported settings in
.env. - Edit
compose.override.yamlfor service-level volumes, environment variables, commands, or other overrides. - Do not edit the official
compose.yaml.
For example:
services:
asp-web:
environment:
EXAMPLE_SETTING: valueApply the change:
docker compose up -d
./scripts/doctor.shRelease packages do not contain .env, compose.override.yaml, or custom/, so overlay upgrades preserve them. See Upgrade.
Next Steps
- Custom Console — Inspect and validate loaded definitions.
- Module Development — Write Redis Stream consumption logic.
- Playbook Development — Write Case-triggered automation.
- SIEM YAML — Maintain index field definitions.
- Restart & Operations — Check service status and logs.