Controls & Frameworks
Controls are policy checks that can be attached to deployments to enforce governance requirements across their lifecycle. A control framework groups a set of controls and applies them to one or more workspaces.
This guide walks through the full workflow:
- Define controls in a CSV file
- Convert the CSV to JSON
- Create controls via the API
- Bundle them into a control framework
CSV format
Controls are defined in a CSV file with the following columns. Column order does not matter; names must match exactly.
| Column | Required | Description |
|---|---|---|
id | ✅ | Short identifier / abbreviation (e.g. CT1, CTRL-001) |
name | ✅ | Human-readable name |
stage | ✅ | Lifecycle stage: exploration, development, validation, or production |
description | ✅ | Detailed description (truncated to 500 characters if longer) |
category | — | Grouping category (free text) |
riskClassifications | — | Comma-separated risk classification tags, or all to target all classifications (see Risk classifications) |
checks | — | Semicolon-separated check definitions (see Checks) |
Example CSV
id,category,stage,name,description,riskClassifications,checks
CT1,Compliance,exploration,Data Privacy Control,Ensure data privacy compliance requirements are met,,
CT2,Governance,development,Model Documentation,Document all model decisions and rationale,all,"type:13, selectedOption:Instructions for use"
CT3,Security,production,Access Control,Implement role-based access control,"high,limited","type:21, matchCondition:includes, selectedOption:Quality Management System; type:8, selectedOption:response time"
CT4,Compliance,validation,Bias Testing,Test for model bias and fairness,limited,"type:7, percentage:80, timeframe:7 days"
CT5,Governance,production,Alert Monitoring,Monitor critical metrics,,"type:7, percentage:80, timeframe:7 days"
CT6,Technical,development,Predictions Made,Ensure minimum prediction volume,high,"type:3, count:50, timeframe:172800000"
CT7,Compliance,validation,Documentation Upload,Required documentation must be present,,"type:21, matchCondition:startsWith, selectedOption:Project Plan"
Risk classifications
| Value | Meaning |
|---|---|
all or leave empty | Applies to all risk classifications (stored as an empty list) |
unacceptable | Unacceptable risk |
high | High risk |
limited | Limited risk |
minimal | Minimal risk |
generalPurposeAI | General Purpose AI |
Multiple values are comma-separated: high,limited. Unknown values are silently dropped with a warning.
Checks
A check is expressed as a comma-separated list of key:value pairs. The type key is always required and refers to the type ID from the table below. Multiple checks on a single control are separated by ;.
type:3, count:50, timeframe:7 days
type:21, matchCondition:includes, selectedOption:Quality Management System; type:8, selectedOption:response time
Timeframe can be written as a human-friendly string (7 days, 1 day) or as an integer number of milliseconds (604800000).
Available check types
| Type ID | Code | Name | Parameters |
|---|---|---|---|
| 0 | PRIVATE_REPOSITORY | Linked repository is private | — |
| 1 | PRIVATE_OBJECT | Artifact stored privately | selectedOption: model | explainer | transformer |
| 2 | DEPLOYMENT_UPDATED | Deployment regularly updated | timeframe |
| 3 | PREDICTIONS_MADE | Deployment Activity | count, timeframe |
| 4 | EXPLAINER_DEPLOYED | Explainer deployed | — |
| 5 | PREDICTIONS_EXPLAINED | Predictions explained | percentage, timeframe |
| 6 | PREDICTIONS_EVALUATED | Evaluations submitted | percentage, timeframe |
| 7 | PREDICTIONS_HAVE_ACTUALS | Actuals submitted | percentage, timeframe |
| 8 | ALERT_RULE_SET | Alert rule added | selectedOption: metric name (e.g. accuracy, response time, feature drift) |
| 9 | DESCRIPTION_AVAILABLE | Description available | — |
| 10 | MODEL_CARD_AVAILABLE | Model card available | — |
| 11 | METADATA_FIELD_SPECIFIED | Metadata field specified | selectedOption: customId | exampleInput | features | … |
| 12 | DATA_CARD_AVAILABLE | Data card available | — |
| 13 | DOCUMENTATION_TEMPLATE_COMPLETED | Documentation template completed | selectedOption: template name (free text) |
| 14 | EVENTS_TRACKED | Events are logged | — |
| 15 | VERSIONS_TRACKED | Version control maintained | — |
| 16 | ALERT_RULE_FOR_PERFORMANCE_SET | Alert rule for performance added | — |
| 17 | USE_CASE_HAS_RISK_CLASSIFICATION | Risk classification assigned | — |
| 18 | USE_CASE_RISK_ASSESSMENT_COMPLETED | Risk classification assessment completed | — |
| 19 | LIFE_CYCLE_STAGES_INCORPORATED | Lifecycle stages incorporated | — |
| 20 | ALERT_RULE_FOR_DRIFT_SET | Alert rule for drift added | — |
| 21 | DOCUMENTATION_UPLOADED | Documentation uploaded | matchCondition: equals | includes | endsWith | startsWith, selectedOption: document name (free text) |
| 22 | GUARDRAILS_ENABLED | Guardrail applied | selectedOption: input | output |
| 23 | PERIODIC_REVIEW | Periodic review | — |
Converting the CSV
The CSV must be converted to a JSON file before uploading to Deeploy. Rows with an invalid stage value are skipped with a warning; all other fields that cannot be parsed are also skipped or defaulted.
Using the CLI
deeploy convert-controls path/to/controls.csv
By default the output is written to <csv_stem>_controls.json next to the input file. Use --output / -o to choose a different destination:
deeploy convert-controls path/to/controls.csv -o path/to/controls.json
Using Python
from deeploy.common.functions.controls_converter import csv_to_controls_json
# Writes controls.json and returns the output path
output_path = csv_to_controls_json("path/to/controls.csv", "path/to/controls.json")
print(f"Written to: {output_path}")
Output format
The resulting JSON is a list of objects, each wrapping a single control:
[
{
"control": {
"abbreviation": "CT3",
"name": "Access Control",
"stage": "production",
"description": "Implement role-based access control",
"category": "Security",
"riskClassifications": ["high", "limited"],
"checks": [
{
"type": 21,
"matchCondition": "includes",
"selectedOption": "Quality Management System"
},
{
"type": 8,
"selectedOption": "response time"
}
]
}
}
]
Creating controls
Pass the loaded JSON list directly to client.create_controls(). The method accepts both the {"control": {...}} wrapper format produced by the converter and plain dicts or CreateControl instances.
import json
from deeploy import Client
from deeploy.common.functions.controls_converter import csv_to_controls_json
# 1. Convert the CSV to JSON
csv_to_controls_json("controls.csv", "controls.json")
# 2. Load the JSON
with open("controls.json") as f:
controls_data = json.load(f)
# 3. Initialise the client
client = Client(
host="<your-host>",
access_key="<your-access-key>",
secret_key="<your-secret-key>",
)
# 4. Create the controls
created = client.create_controls(controls_data)
print(f"Created {len(created)} controls")
create_controls returns a list of Control objects. Each object has an id field that is needed when building a framework.
create_controls does not require a workspace_id on the client because controls are organization-level resources, not workspace-scoped.
Creating a control framework
A framework groups controls and optionally assigns them to specific workspaces.
framework = client.create_control_framework({
"name": "My Governance Framework",
"description": "Core controls for all production deployments",
"control_ids": [c.id for c in created],
"workspace_ids": [], # empty list = not yet assigned to any workspace
})
print(f"Framework created: {framework.id}")
End-to-end example
import json
from deeploy import Client
from deeploy.common.functions.controls_converter import csv_to_controls_json
# Convert CSV → JSON
csv_to_controls_json("controls.csv", "controls.json")
with open("controls.json") as f:
controls_data = json.load(f)
# Create client
client = Client(
host="<your-host>",
access_key="<your-access-key>",
secret_key="<your-secret-key>",
)
# Create controls
created = client.create_controls(controls_data)
# Bundle into a framework
framework = client.create_control_framework({
"name": "My Governance Framework",
"description": "Core controls for all production deployments",
"control_ids": [c.id for c in created],
"workspace_ids": [],
})
print(f"Framework '{framework.name}' created with {len(framework.controls)} controls")