AI Config Targeting
Configure targeting rules for AI Configs to control which variations serve to different contexts. Works the same for both completion and agent mode.
Prerequisites
-
LaunchDarkly account with AI Configs enabled
-
API access token with write permissions
-
Project key and environment key
-
Existing AI Config with variations (use aiconfig-create skill)
API Key Detection
-
Check environment variables - LAUNCHDARKLY_API_KEY , LAUNCHDARKLY_API_TOKEN , LD_API_KEY
-
Check MCP config - Claude: ~/.claude/config.json -> mcpServers.launchdarkly.env.LAUNCHDARKLY_API_KEY
-
Prompt user - Only if detection fails
Core Concepts
Evaluation Order
Targeting rules evaluate in this order (same as feature flags):
-
Individual targets - Specific context keys (highest priority)
-
Segment rules - Pre-defined segments
-
Custom rules - Attribute-based conditions (evaluated in order)
-
Default rule - Fallthrough for all others
-
Off variation - When targeting is disabled
Semantic Patch API
AI Config targeting uses semantic patch instructions:
PATCH /api/v2/projects/{projectKey}/ai-configs/{configKey}/targeting Content-Type: application/json; domain-model=launchdarkly.semanticpatch
Key Concepts
-
variationId: UUIDs, not keys. Always fetch targeting first to get IDs.
-
Weights: Thousandths (50000 = 50%, 100000 = 100%)
-
Clause logic: Multiple clauses = AND, multiple values = OR
-
Null attributes: Rules with null/missing attributes are skipped
Workflow
Step 1: Get Targeting (with Variation IDs)
curl -X GET "https://app.launchdarkly.com/api/v2/projects/{projectKey}/ai-configs/{configKey}/targeting"
-H "Authorization: {api_token}"
-H "LD-API-Version: beta"
Response includes variations array with _id (UUID) for each variation.
Step 2: Edit the Default Rule
Edit the default rule to serve the variation you created.
Important: The turnTargetingOn instruction does not work for AI Configs. Use updateFallthroughVariationOrRollout instead.
First, get variation IDs from Step 1 response
Then set fallthrough to the enabled variation (e.g., "Default" variation)
curl -X PATCH "https://app.launchdarkly.com/api/v2/projects/{projectKey}/ai-configs/{configKey}/targeting"
-H "Authorization: {api_token}"
-H "Content-Type: application/json; domain-model=launchdarkly.semanticpatch"
-H "LD-API-Version: beta"
-d '{
"environmentKey": "production",
"instructions": [{
"kind": "updateFallthroughVariationOrRollout",
"variationId": "your-enabled-variation-uuid"
}]
}'
Step 3: Add Targeting Rules
Attribute-based rule:
curl -X PATCH "https://app.launchdarkly.com/api/v2/projects/{projectKey}/ai-configs/{configKey}/targeting"
-H "Authorization: {api_token}"
-H "Content-Type: application/json; domain-model=launchdarkly.semanticpatch"
-H "LD-API-Version: beta"
-d '{
"environmentKey": "production",
"instructions": [{
"kind": "addRule",
"clauses": [{
"contextKind": "user",
"attribute": "selectedModel",
"op": "contains",
"values": ["sonnet"],
"negate": false
}],
"variation": 0
}]
}'
Percentage rollout:
curl -X PATCH "..."
-d '{
"environmentKey": "production",
"instructions": [{
"kind": "addRule",
"clauses": [{
"contextKind": "user",
"attribute": "tier",
"op": "in",
"values": ["premium"],
"negate": false
}],
"percentageRolloutConfig": {
"contextKind": "user",
"bucketBy": "key",
"variations": [
{"variation": 0, "weight": 60000},
{"variation": 1, "weight": 40000}
]
}
}]
}'
Set fallthrough (default rule):
curl -X PATCH "..."
-d '{
"environmentKey": "production",
"instructions": [{
"kind": "updateFallthroughVariationOrRollout",
"variationId": "fallback-variation-uuid"
}]
}'
Python Implementation
import requests import os from typing import Dict, List, Optional
class AIConfigTargeting: """Manager for AI Config targeting rules"""
def __init__(self, api_token: str, project_key: str):
self.api_token = api_token
self.project_key = project_key
self.base_url = "https://app.launchdarkly.com/api/v2"
def get_targeting(self, config_key: str) -> Optional[Dict]:
"""Get current targeting with variation IDs."""
url = f"{self.base_url}/projects/{self.project_key}/ai-configs/{config_key}/targeting"
response = requests.get(url, headers={
"Authorization": self.api_token,
"LD-API-Version": "beta"
})
if response.status_code == 200:
return response.json()
print(f"[ERROR] {response.status_code}: {response.text}")
return None
def get_variation_id(self, config_key: str, variation_key: str) -> Optional[str]:
"""Look up variation UUID from key or name."""
targeting = self.get_targeting(config_key)
if targeting:
for var in targeting.get("variations", []):
if var.get("key") == variation_key or var.get("name") == variation_key:
return var.get("_id")
return None
def update_targeting(self, config_key: str, environment: str,
instructions: List[Dict], comment: str = "") -> Optional[Dict]:
"""Send semantic patch instructions."""
url = f"{self.base_url}/projects/{self.project_key}/ai-configs/{config_key}/targeting"
payload = {"environmentKey": environment, "instructions": instructions}
if comment:
payload["comment"] = comment
response = requests.patch(url, headers={
"Authorization": self.api_token,
"Content-Type": "application/json; domain-model=launchdarkly.semanticpatch",
"LD-API-Version": "beta"
}, json=payload)
if response.status_code == 200:
return response.json()
print(f"[ERROR] {response.status_code}: {response.text}")
return None
def enable_config(self, config_key: str, environment: str,
variation_key: str = "default") -> bool:
"""
Enable an AI Config by setting fallthrough to an enabled variation.
Note: turnTargetingOn doesn't work for AI Configs. Instead, set the
fallthrough from the disabled variation (index 0) to an enabled one.
"""
variation_id = self.get_variation_id(config_key, variation_key)
if not variation_id:
print(f"[ERROR] Variation '{variation_key}' not found")
return False
return self.set_fallthrough(config_key, environment, variation_id)
def add_rule(self, config_key: str, environment: str,
clauses: List[Dict], variation: int,
description: str = "") -> bool:
"""Add targeting rule serving a specific variation index."""
instruction = {
"kind": "addRule",
"clauses": clauses,
"variation": variation
}
if description:
instruction["description"] = description
result = self.update_targeting(config_key, environment,
[instruction], f"Add rule: {description}")
if result:
print(f"[OK] Rule added")
return True
return False
def add_rollout_rule(self, config_key: str, environment: str,
clauses: List[Dict],
weights: List[Dict],
bucket_by: str = "key") -> bool:
"""
Add percentage rollout rule.
weights: [{"variation": 0, "weight": 50000}, {"variation": 1, "weight": 50000}]
"""
result = self.update_targeting(config_key, environment, [{
"kind": "addRule",
"clauses": clauses,
"percentageRolloutConfig": {
"contextKind": "user",
"bucketBy": bucket_by,
"variations": weights
}
}], "Add percentage rollout")
if result:
print(f"[OK] Rollout rule added")
return True
return False
def set_fallthrough(self, config_key: str, environment: str,
variation_id: str) -> bool:
"""Set default (fallthrough) variation by UUID."""
result = self.update_targeting(config_key, environment, [{
"kind": "updateFallthroughVariationOrRollout",
"variationId": variation_id
}], "Set fallthrough")
if result:
print(f"[OK] Fallthrough set")
return True
return False
def target_individuals(self, config_key: str, environment: str,
context_keys: List[str], variation: int,
context_kind: str = "user") -> bool:
"""Target specific context keys."""
result = self.update_targeting(config_key, environment, [{
"kind": "addTargets",
"variation": variation,
"contextKind": context_kind,
"values": context_keys
}], f"Target {len(context_keys)} individuals")
if result:
print(f"[OK] Individual targets added")
return True
return False
def target_segment(self, config_key: str, environment: str,
segment_keys: List[str], variation: int) -> bool:
"""Target a segment."""
result = self.update_targeting(config_key, environment, [{
"kind": "addRule",
"clauses": [{
"attribute": "segmentMatch",
"contextKind": "", # Leave blank for segments
"op": "segmentMatch",
"values": segment_keys,
"negate": False
}],
"variation": variation
}], f"Target segments: {segment_keys}")
if result:
print(f"[OK] Segment targeting added")
return True
return False
def clear_rules(self, config_key: str, environment: str) -> bool:
"""Remove all targeting rules."""
result = self.update_targeting(config_key, environment,
[{"kind": "replaceRules", "rules": []}], "Clear all rules")
if result:
print(f"[OK] All rules cleared")
return True
return False
Instruction Reference
Note: turnTargetingOn and turnTargetingOff do not work for AI Configs. AI Configs have targeting enabled by default. To "enable" a config, set the fallthrough to an enabled variation using updateFallthroughVariationOrRollout .
Rules
Kind Description
addRule
Add rule with clauses and variation/rollout
removeRule
Remove by ruleId
replaceRules
Replace all rules
reorderRules
Change evaluation order
updateRuleVariationOrRollout
Update what a rule serves
Fallthrough
Kind Description
updateFallthroughVariationOrRollout
Set default variation or rollout
Individual Targets
Kind Description
addTargets
Target specific context keys
removeTargets
Remove specific targets
replaceTargets
Replace all targets
Operators Reference
Operator Description Example
in
Value in list ["premium", "enterprise"]
contains
String contains ["sonnet"]
startsWith
String prefix ["user-"]
endsWith
String suffix [".edu"]
matches
Regex match ["^user-\d+$"]
greaterThan / lessThan
Numeric comparison [100]
before / after
Date comparison ["2024-12-31T00:00:00Z"]
semVerEqual / semVerGreaterThan
Version comparison ["2.0.0"]
segmentMatch
Segment membership ["beta-testers"]
Clause Structure
{ "contextKind": "user", "attribute": "email", "op": "endsWith", "values": [".edu"], "negate": false }
-
Multiple clauses = AND (all must match)
-
Multiple values = OR (any can match)
-
negate: true inverts the operator
Rollout Types
Manual Percentage Rollout
{ "percentageRolloutConfig": { "contextKind": "user", "bucketBy": "key", "variations": [ {"variation": 0, "weight": 50000}, {"variation": 1, "weight": 50000} ] } }
Progressive Rollout
{ "progressiveRolloutConfig": { "contextKind": "user", "controlVariation": 1, "endVariation": 0, "steps": [ {"rolloutWeight": 1000, "duration": {"quantity": 4, "unit": "hour"}}, {"rolloutWeight": 5000, "duration": {"quantity": 4, "unit": "hour"}}, {"rolloutWeight": 10000, "duration": {"quantity": 4, "unit": "hour"}} ] } }
Guarded Rollout
{ "guardedRolloutConfig": { "randomizationUnit": "user", "stages": [ {"rolloutWeight": 1000, "monitoringWindowMilliseconds": 17280000}, {"rolloutWeight": 5000, "monitoringWindowMilliseconds": 17280000} ], "metrics": [{ "metricKey": "error-rate", "onRegression": {"rollback": true}, "regressionThreshold": 0.01 }] } }
Common Patterns
Model Routing by Attribute
Route based on selectedModel context attribute
targeting.add_rule( config_key="model-selector", environment="production", clauses=[{ "contextKind": "user", "attribute": "selectedModel", "op": "contains", "values": ["sonnet"], "negate": False }], variation=0, # Sonnet variation index description="Route sonnet requests" )
Tier-Based Variation
targeting.add_rule( config_key="chat-assistant", environment="production", clauses=[{ "contextKind": "user", "attribute": "tier", "op": "in", "values": ["premium", "enterprise"], "negate": False }], variation=0 # Premium model variation )
Segment Targeting
targeting.target_segment( config_key="chat-assistant", environment="production", segment_keys=["beta-testers"], variation=1 # Experimental variation )
Error Handling
Status Cause Solution
400 Invalid semantic patch Check instruction format, ops must be lowercase
403 Insufficient permissions Check API token
404 Config not found Verify projectKey and configKey
422 Invalid variation Use index (0, 1, 2...) or UUID from targeting response
Next Steps
After configuring targeting:
-
Provide config URL: https://app.launchdarkly.com/projects/{projectKey}/ai-configs/{configKey}
-
Monitor performance with aiconfig-ai-metrics
-
Attach judges with aiconfig-online-evals
-
Set up guarded rollouts for automatic regression detection
Related Skills
-
aiconfig-create
-
Create AI Configs with variations
-
aiconfig-variations
-
Manage variations
-
aiconfig-online-evals
-
Attach judges
-
aiconfig-segments
-
Create segments for targeting
References
-
Target with AI Configs
-
Targeting Rules
-
JSON Targeting
-
Guarded Rollouts