$npx -y skills add launchdarkly/ai-tooling --skill configs-targetingConfigure config targeting rules to control which variations serve to different users. Enable percentage rollouts, attribute-based rules, segment targeting, and guarded rollouts.
| 1 | # Config Targeting |
| 2 | |
| 3 | Configure targeting rules for configs to control which variations serve to different contexts. Works the same for both completion and agent mode. |
| 4 | |
| 5 | ## Prerequisites |
| 6 | |
| 7 | - LaunchDarkly account with AgentControl enabled |
| 8 | - API access token with write permissions |
| 9 | - Project key and environment key |
| 10 | - Existing config with variations (use `configs-create` skill) |
| 11 | |
| 12 | ## API Key Detection |
| 13 | |
| 14 | 1. **Check environment variables** - `LAUNCHDARKLY_API_KEY`, `LAUNCHDARKLY_API_TOKEN`, `LD_API_KEY` |
| 15 | 2. **Check MCP config** - Claude: `~/.claude/config.json` -> `mcpServers.launchdarkly.env.LAUNCHDARKLY_API_KEY` |
| 16 | 3. **Prompt user** - Only if detection fails |
| 17 | |
| 18 | ## Core Concepts |
| 19 | |
| 20 | ### Evaluation Order |
| 21 | |
| 22 | Targeting rules evaluate in this order (same as feature flags): |
| 23 | |
| 24 | 1. **Individual targets** - Specific context keys (highest priority) |
| 25 | 2. **Segment rules** - Pre-defined segments |
| 26 | 3. **Custom rules** - Attribute-based conditions (evaluated in order) |
| 27 | 4. **Default rule** - Fallthrough for all others |
| 28 | 5. **Off variation** - When targeting is disabled |
| 29 | |
| 30 | ### Semantic Patch API |
| 31 | |
| 32 | config targeting uses semantic patch instructions: |
| 33 | |
| 34 | ``` |
| 35 | PATCH /api/v2/projects/{projectKey}/ai-configs/{configKey}/targeting |
| 36 | Content-Type: application/json; domain-model=launchdarkly.semanticpatch |
| 37 | ``` |
| 38 | |
| 39 | ### Key Concepts |
| 40 | |
| 41 | - **variationId**: UUIDs, not keys. Always fetch targeting first to get IDs. |
| 42 | - **Weights**: Thousandths (50000 = 50%, 100000 = 100%) |
| 43 | - **Clause logic**: Multiple clauses = AND, multiple values = OR |
| 44 | - **Null attributes**: Rules with null/missing attributes are skipped |
| 45 | |
| 46 | ## Workflow |
| 47 | |
| 48 | ### Step 1: Get Targeting (with Variation IDs) |
| 49 | |
| 50 | ```bash |
| 51 | curl -X GET "https://app.launchdarkly.com/api/v2/projects/{projectKey}/ai-configs/{configKey}/targeting" \ |
| 52 | -H "Authorization: {api_token}" \ |
| 53 | -H "LD-API-Version: beta" |
| 54 | ``` |
| 55 | |
| 56 | Response includes `variations` array with `_id` (UUID) for each variation. |
| 57 | |
| 58 | ### Step 2: Edit the Default Rule |
| 59 | |
| 60 | Edit the default rule to serve the variation you created. |
| 61 | |
| 62 | > **Important:** The `turnTargetingOn` instruction does not work for configs. Use `updateFallthroughVariationOrRollout` instead. |
| 63 | |
| 64 | ```bash |
| 65 | # First, get variation IDs from Step 1 response |
| 66 | # Then set fallthrough to the enabled variation (e.g., "Default" variation) |
| 67 | curl -X PATCH "https://app.launchdarkly.com/api/v2/projects/{projectKey}/ai-configs/{configKey}/targeting" \ |
| 68 | -H "Authorization: {api_token}" \ |
| 69 | -H "Content-Type: application/json; domain-model=launchdarkly.semanticpatch" \ |
| 70 | -H "LD-API-Version: beta" \ |
| 71 | -d '{ |
| 72 | "environmentKey": "production", |
| 73 | "instructions": [{ |
| 74 | "kind": "updateFallthroughVariationOrRollout", |
| 75 | "variationId": "your-enabled-variation-uuid" |
| 76 | }] |
| 77 | }' |
| 78 | ``` |
| 79 | |
| 80 | ### Step 3: Add Targeting Rules |
| 81 | |
| 82 | **Attribute-based rule:** |
| 83 | |
| 84 | ```bash |
| 85 | curl -X PATCH "https://app.launchdarkly.com/api/v2/projects/{projectKey}/ai-configs/{configKey}/targeting" \ |
| 86 | -H "Authorization: {api_token}" \ |
| 87 | -H "Content-Type: application/json; domain-model=launchdarkly.semanticpatch" \ |
| 88 | -H "LD-API-Version: beta" \ |
| 89 | -d '{ |
| 90 | "environmentKey": "production", |
| 91 | "instructions": [{ |
| 92 | "kind": "addRule", |
| 93 | "clauses": [{ |
| 94 | "contextKind": "user", |
| 95 | "attribute": "selectedModel", |
| 96 | "op": "contains", |
| 97 | "values": ["sonnet"], |
| 98 | "negate": false |
| 99 | }], |
| 100 | "variation": 0 |
| 101 | }] |
| 102 | }' |
| 103 | ``` |
| 104 | |
| 105 | **Percentage rollout:** |
| 106 | |
| 107 | ```bash |
| 108 | curl -X PATCH "..." \ |
| 109 | -d '{ |
| 110 | "environmentKey": "production", |
| 111 | "instructions": [{ |
| 112 | "kind": "addRule", |
| 113 | "clauses": [{ |
| 114 | "contextKind": "user", |
| 115 | "attribute": "tier", |
| 116 | "op": "in", |
| 117 | "values": ["premium"], |
| 118 | "negate": false |
| 119 | }], |
| 120 | "percentageRolloutConfig": { |
| 121 | "contextKind": "user", |
| 122 | "bucketBy": "key", |
| 123 | "variations": [ |
| 124 | {"variation": 0, "weight": 60000}, |
| 125 | {"variation": 1, "weight": 40000} |
| 126 | ] |
| 127 | } |
| 128 | }] |
| 129 | }' |
| 130 | ``` |
| 131 | |
| 132 | **Set fallthrough (default rule):** |
| 133 | |
| 134 | ```bash |
| 135 | curl -X PATCH "..." \ |
| 136 | -d '{ |
| 137 | "environmentKey": "production", |
| 138 | "instructions": [{ |
| 139 | "kind": "updateFallthroughVariationOrRollout", |
| 140 | "variationId": "fallback-variation-uuid" |
| 141 | }] |
| 142 | }' |
| 143 | ``` |
| 144 | |
| 145 | ## Python Implementation |
| 146 | |
| 147 | ```python |
| 148 | import requests |
| 149 | import os |
| 150 | from typing import Dict, List, Optional |
| 151 | |
| 152 | class AIConfigTargeting: |
| 153 | """Manager for config targeting rules""" |
| 154 | |
| 155 | def __init__(self, api_token: str, project_key: str): |
| 156 | self.api_token = api_token |
| 157 | self.project_key = project_key |
| 158 | self.base_url = "https://app.launchdarkly.com/api/v2" |
| 159 | |
| 160 | def get_targeting(self, config_key: str) -> Optional[Dict]: |
| 161 | """Get current targeting with variation IDs.""" |
| 162 | url = f"{self.base_url}/p |