- 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