Skip to content

Download Guardrails

Available Guides

Understanding Guardrail Downloads

There are two distinct CSV formats related to Guardrails. It is important to understand their differences before downloading.

Feature Table View CSV Import Guardrails CSV
Purpose Reporting and analysis Programmatic bulk import
Target audience Operations Platform Administrators and Developers
Format Human-readable values (e.g., "Enabled", "Disabled") Programmatic values (booleans, KRN terminology)
Content Depends on visible table columns Fixed schema with all guardrail fields
Can be re-imported? No Yes, via the Import Guardrails feature

Warning

The CSV file downloaded from the Guardrails table view cannot be used with the Import Guardrails feature. These have completely different structures and purposes.

  • Table View CSV — Designed for Operations teams. The columns and values reflect what is currently visible in the table, using friendly labels such as "Enabled" and "Disabled" instead of boolean values.
  • Import Guardrails CSV — A programmatically defined file that must follow the Import Guardrails CSV format, using booleans, strings, and KRN terminology.

You can download a blank Import Guardrails CSV template from the Import Guardrails dialog in the Kelvin UI.

Reference:

Field Description
resource Asset / Data Stream pair in KRN format. The KRN format is krn:ad:<asset_name>/<data_stream_name>
control_disabled Whether the Guardrail control is disabled (true or false).
number Object containing min, max, and relative guardrail limit configurations.
number.min.value Minimum allowed value for the data stream.
number.min.type Type of the minimum value (number or datastream).
number.min.inclusive Whether the minimum boundary is inclusive (true or false).
number.max.value Maximum allowed value for the data stream.
number.max.type Type of the maximum value (number or datastream).
number.max.inclusive Whether the maximum boundary is inclusive (true or false).
number.relative.increase Object containing min and max limits for relative increases.
number.relative.decrease Object containing min and max limits for relative decreases.

Download a Guardrail

In this example we will download a single Guardrail for an Asset / Data Stream pair. The resource is krn:ad:pcp_01/speed_sp.

There is no Kelvin UI option to download individual guardrail data in a programmatic format. The table view download provides a human-readable CSV for reporting purposes only.

API cURL Example
1
2
3
4
curl -X "GET" \
  "https://<url.kelvin.ai>/api/v4/guardrails/krn%3Aad%3Apcp_01%2Fspeed_sp/get" \
  -H "Authorization: Bearer <Your Current Token>" \
  -H "Accept: application/json"

You will receive a response body with a status code of 200, indicating a successful operation.

For example, the response body might look like this:

API cURL Example Response
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
{
  "resource": "krn:ad:pcp_01/speed_sp",
  "control_disabled": false,
  "number": {
    "min": {
      "value": 0,
      "inclusive": true
    },
    "max": {
      "value": 100,
      "inclusive": true
    },
    "relative": {
      "increase": {},
      "decrease": {}
    }
  }
}
API Client (Python) Example
 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
import requests
import urllib.parse
import os

# Configuration
AUTH_URL = "https://<url.kelvin.ai>/auth/realms/kelvin/protocol/openid-connect/token"
API_BASE_URL = "https://<url.kelvin.ai>/api/v4/guardrails/"
USERNAME = os.environ["KELVIN_USERNAME"]
PASSWORD = os.environ["KELVIN_PASSWORD"]

# Authenticate
token_response = requests.post(AUTH_URL, data={
    "username": USERNAME,
    "password": PASSWORD,
    "client_id": "kelvin-client",
    "grant_type": "password"
}, headers={"Content-Type": "application/x-www-form-urlencoded"})
token_response.raise_for_status()
token = token_response.json()["access_token"]

# Fetch Guardrail
resource = "krn:ad:pcp_01/speed_sp"
escaped_resource = urllib.parse.quote(resource, safe="")
url = f"{API_BASE_URL}{escaped_resource}/get"
response = requests.get(url, headers={
    "Authorization": f"Bearer {token}",
    "Accept": "application/json"
})
response.raise_for_status()

print(response.json())

The response will look like this:

API Client (Python) Example Response
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
{
  "resource": "krn:ad:pcp_01/speed_sp",
  "control_disabled": false,
  "number": {
    "min": {
      "value": 0,
      "inclusive": true
    },
    "max": {
      "value": 100,
      "inclusive": true
    },
    "relative": {
      "increase": {},
      "decrease": {}
    }
  }
}

Update a Guardrail via API

You can download a guardrail, modify the JSON response, and then update it using the API. Kelvin will ignore keys that are not required for the update, so you can supply the full GET response as the body.

Step 1: Download the guardrail using the GET endpoint (see Download a Guardrail above).

Step 2: Modify the JSON response as needed (e.g., change the min or max values).

Step 3: Submit the modified JSON as the body of the update request:

API cURL Example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
curl -X "POST" \
  "https://<url.kelvin.ai>/api/v4/guardrails/krn%3Aad%3Apcp_01%2Fspeed_sp/update" \
  -H "Authorization: Bearer <Your Current Token>" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
        "resource": "krn:ad:pcp_01/speed_sp",
        "control_disabled": false,
        "number": {
          "min": {
            "value": 10,
            "inclusive": true
          },
          "max": {
            "value": 90,
            "inclusive": true
          }
        }
      }'

You will receive a response body with a status code of 200, indicating a successful operation.

Export Guardrails to Import-Compatible CSV

If you need to export all guardrails into a CSV file that is compatible with the Import Guardrails feature, you can use the following Python script.

Warning

Importing the generated CSV file will create new guardrail entries. It will not update existing guardrails. Test on a small scale first before importing in bulk.

Note

Set the KELVIN_USERNAME and KELVIN_PASSWORD environment variables before running the script.

export_guardrails.py
  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
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import csv
import requests
import os
import urllib.parse

# --- Configuration ---
guardrail_resources = [
    "krn:ad:beam_pump_01/speed_spm_sp",
    "krn:ad:pcp_01/speed_sp",
]  # Add more resources as needed

API_BASE_URL = os.environ.get(
    "GUARDRAIL_API_BASE_URL",
    "https://<url.kelvin.ai>/api/v4/guardrails/",
)
AUTH_URL = os.environ.get(
    "GUARDRAIL_AUTH_URL",
    "https://<url.kelvin.ai>/auth/realms/kelvin/protocol/openid-connect/token",
)
AUTH_USERNAME = os.environ.get("KELVIN_USERNAME")
AUTH_PASSWORD = os.environ.get("KELVIN_PASSWORD")
OUTPUT_CSV = "guardrails_export.csv"

CSV_HEADER = [
    "Asset",
    "Data Stream",
    "Control",
    "Minimum Value",
    "Minimum Value Type",
    "Minimum Value Included",
    "Maximum Value",
    "Maximum Value Type",
    "Maximum Value Included",
    "Relative Increase Minimum Value",
    "Relative Increase Minimum Value Type",
    "Relative Increase Minimum Value Included",
    "Relative Increase Maximum Value",
    "Relative Increase Maximum Value Type",
    "Relative Increase Maximum Value Included",
    "Relative Decrease Minimum Value",
    "Relative Decrease Minimum Value Type",
    "Relative Decrease Minimum Value Included",
    "Relative Decrease Maximum Value",
    "Relative Decrease Maximum Value Type",
    "Relative Decrease Maximum Value Included",
]


def get_auth_token():
    data = {
        "username": AUTH_USERNAME,
        "password": AUTH_PASSWORD,
        "client_id": "kelvin-client",
        "grant_type": "password",
    }
    headers = {"Content-Type": "application/x-www-form-urlencoded"}
    response = requests.post(AUTH_URL, data=data, headers=headers)
    response.raise_for_status()
    token = response.json().get("access_token")
    if not token:
        raise Exception("Failed to obtain access token.")
    return token


def fetch_guardrail_data(resource, token):
    escaped_resource = urllib.parse.quote(resource, safe="")
    url = f"{API_BASE_URL}{escaped_resource}/get"
    headers = {
        "Authorization": f"Bearer {token}",
        "accept": "application/json",
    }
    response = requests.get(url, headers=headers)
    response.raise_for_status()
    return response.json()


def parse_guardrail_to_row(data):
    def get_nested(dct, *keys):
        for key in keys:
            if not isinstance(dct, dict):
                return ""
            dct = dct.get(key)
            if dct is None:
                return ""
        return dct

    resource = data.get("resource", "")
    asset = resource.split("/")[0].replace("krn:ad:", "") if resource else ""
    datastream = resource.split("/")[-1] if "/" in resource else ""
    control = data.get("control_disabled", "")
    number = data.get("number", {})

    min_value = get_nested(number, "min", "value")
    min_type = get_nested(number, "min", "type")
    min_included = get_nested(number, "min", "inclusive")
    max_value = get_nested(number, "max", "value")
    max_type = get_nested(number, "max", "type")
    max_included = get_nested(number, "max", "inclusive")

    relative = number.get("relative", {}) or {}
    increase = relative.get("increase", {}) or {}
    rel_inc_min_value = get_nested(increase, "min", "value")
    rel_inc_min_type = get_nested(increase, "min", "type")
    rel_inc_min_included = get_nested(increase, "min", "inclusive")
    rel_inc_max_value = get_nested(increase, "max", "value")
    rel_inc_max_type = get_nested(increase, "max", "type")
    rel_inc_max_included = get_nested(increase, "max", "inclusive")

    decrease = relative.get("decrease", {}) or {}
    rel_dec_min_value = get_nested(decrease, "min", "value")
    rel_dec_min_type = get_nested(decrease, "min", "type")
    rel_dec_min_included = get_nested(decrease, "min", "inclusive")
    rel_dec_max_value = get_nested(decrease, "max", "value")
    rel_dec_max_type = get_nested(decrease, "max", "type")
    rel_dec_max_included = get_nested(decrease, "max", "inclusive")

    return [
        asset, datastream, control,
        min_value, min_type, min_included,
        max_value, max_type, max_included,
        rel_inc_min_value, rel_inc_min_type, rel_inc_min_included,
        rel_inc_max_value, rel_inc_max_type, rel_inc_max_included,
        rel_dec_min_value, rel_dec_min_type, rel_dec_min_included,
        rel_dec_max_value, rel_dec_max_type, rel_dec_max_included,
    ]


def export_guardrails_to_csv(resources, output_csv):
    token = get_auth_token()
    with open(output_csv, mode="w", newline="") as csvfile:
        writer = csv.writer(csvfile)
        writer.writerow(CSV_HEADER)
        for resource in resources:
            try:
                data = fetch_guardrail_data(resource, token)
                row = parse_guardrail_to_row(data)
                writer.writerow(row)
            except Exception as e:
                print(f"Failed to export guardrail {resource}: {e}")


if __name__ == "__main__":
    export_guardrails_to_csv(guardrail_resources, OUTPUT_CSV)
    print(f"Exported guardrails to {OUTPUT_CSV}")

Example output CSV:

guardrails_export.csv
Asset,Data Stream,Control,Minimum Value,Minimum Value Type,Minimum Value Included,Maximum Value,Maximum Value Type,Maximum Value Included,Relative Increase Minimum Value,Relative Increase Minimum Value Type,Relative Increase Minimum Value Included,Relative Increase Maximum Value,Relative Increase Maximum Value Type,Relative Increase Maximum Value Included,Relative Decrease Minimum Value,Relative Decrease Minimum Value Type,Relative Decrease Minimum Value Included,Relative Decrease Maximum Value,Relative Decrease Maximum Value Type,Relative Decrease Maximum Value Included
beam_pump_01,speed_spm_sp,False,10,,True,500,,True,,,,,,,,,,,,
pcp_01,speed_sp,False,0,,True,100,,True,,,,,,,,,,,,

This CSV file follows the same format as the Import Guardrails CSV template and can be used with the Import Guardrails feature.