diff --git a/README.md b/README.md index 660e91b..6fa3557 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Agent Skills are modular, text-based playbooks that teach an agent how to perfor | `feature-flags/launchdarkly-flag-create` | Create new feature flags in a way that fits existing codebase patterns | | `feature-flags/launchdarkly-flag-targeting` | Control targeting, rollouts, rules, and cross-environment config | | `feature-flags/launchdarkly-flag-cleanup` | Safely remove flags from code using LaunchDarkly as the source of truth | +| `feature-flags/launchdarkly-segment-create` | Create reusable audience segments with targeting rules or individual targets, and wire them into flags | ### AI Configs diff --git a/skills.json b/skills.json index f3837f2..e1bc2c1 100644 --- a/skills.json +++ b/skills.json @@ -109,6 +109,14 @@ "devops", "mcp" ] + }, + { + "name": "launchdarkly-segment-create", + "description": "Create and configure LaunchDarkly segments \u2014 reusable audience definitions for flag targeting. Use when the user wants to create a segment, add targeting rules to a segment, add individual contexts to a segment, or wire an existing segment into a feature flag's targeting rules.", + "path": "skills/feature-flags/launchdarkly-segment-create", + "version": "1.0.0-experimental", + "license": "Apache-2.0", + "compatibility": "Requires the remotely hosted LaunchDarkly MCP server" } ] } diff --git a/skills/feature-flags/launchdarkly-segment-create/README.md b/skills/feature-flags/launchdarkly-segment-create/README.md new file mode 100644 index 0000000..a6fb048 --- /dev/null +++ b/skills/feature-flags/launchdarkly-segment-create/README.md @@ -0,0 +1,50 @@ +# LaunchDarkly Segment Create Skill + +An Agent Skill for creating and managing reusable audience segments in LaunchDarkly, so teams define targeting criteria once and reuse them across multiple feature flags. + +## Overview + +This skill teaches agents how to: +- Check for existing segments before creating duplicates +- Choose the right segment type: rule-based (attribute matching) vs list-based (explicit keys) +- Create a segment in a specific environment with the right key, name, and tags +- Configure segment membership via targeting rules or individual context targets +- Wire a segment into a feature flag's targeting rules using the `segmentMatch` operator + +## Usage + +Once installed, the skill activates when you ask about segments: + +``` +Create a beta-testers segment in staging for users whose email ends in @example.com +``` + +``` +Add the enterprise-accounts segment to the new-dashboard flag so enterprise users get the true variation +``` + +``` +Set up an internal-qa segment in production with these specific user keys: [key1, key2, key3] +``` + +## Structure + +``` +launchdarkly-segment-create/ +├── SKILL.md +├── README.md +└── references/ + ├── segment-types.md + └── segment-rule-patterns.md +``` + +## Related + +- [LaunchDarkly Flag Targeting](../launchdarkly-flag-targeting/) — Wire segments into flag targeting rules after creating them +- [LaunchDarkly Flag Create](../launchdarkly-flag-create/) — Create the flags that segments will be wired into +- [LaunchDarkly MCP Server](https://github.com/launchdarkly/mcp-server) +- [LaunchDarkly Segments Docs](https://launchdarkly.com/docs/home/flags/segments) + +## License + +Apache-2.0 diff --git a/skills/feature-flags/launchdarkly-segment-create/SKILL.md b/skills/feature-flags/launchdarkly-segment-create/SKILL.md new file mode 100644 index 0000000..b6e90dd --- /dev/null +++ b/skills/feature-flags/launchdarkly-segment-create/SKILL.md @@ -0,0 +1,167 @@ +--- +name: launchdarkly-segment-create +description: "Create and configure LaunchDarkly segments — reusable audience definitions for flag targeting. Use when the user wants to create a segment, add targeting rules to a segment, add individual contexts to a segment, or wire an existing segment into a feature flag's targeting rules." +license: Apache-2.0 +compatibility: Requires the remotely hosted LaunchDarkly MCP server +metadata: + author: launchdarkly + version: "1.0.0-experimental" +--- + +# LaunchDarkly Segment Create & Configure + +You're using a skill that will guide you through creating a reusable audience segment in LaunchDarkly. Your job is to explore what segments already exist, choose the right segment type, create the segment, configure its membership through rules or individual targets, and optionally wire it into a feature flag's targeting rules. + +## Prerequisites + +This skill requires the remotely hosted LaunchDarkly MCP server to be configured in your environment. + +**Required MCP tools:** +- `list-segments` — check what segments already exist before creating one +- `create-segment` — create a new rule-based or list-based segment in an environment +- `get-segment` — verify the segment was created and configured correctly + +**Configuration tools (use the one that matches the segment's membership model):** +- `update-segment-rules` — add or modify attribute-based targeting rules +- `update-segment-targets` — add or remove individual context keys + +**Optional MCP tool (to wire the segment into a flag):** +- `update-targeting-rules` — add a `segmentMatch` rule to an existing feature flag + +## Core Principles + +1. **Check before creating.** A segment with the same name or purpose may already exist. Avoid creating duplicates by listing segments first and checking for overlap. +2. **Segment type drives the configuration path.** Rule-based segments match contexts by attribute (email, plan tier, country). List-based segments target specific keys explicitly. The right type depends on whether the audience is defined by attributes or by identity. See [Segment Types](references/segment-types.md). +3. **Segments are environment-specific.** A segment created in `staging` does not exist in `production`. If the segment needs to exist in multiple environments, it must be created separately in each. +4. **The segment key is immutable.** Once created, the key cannot be changed. Choose it carefully — use `kebab-case`, match the project's existing naming convention, and make it descriptive. + +## Workflow + +### Step 1: Explore Existing Segments + +Before creating anything, confirm the environment and check what already exists. + +1. **Confirm the environment.** Segments are environment-specific. Always confirm which environment the user is targeting before proceeding. If not specified, ask rather than assume. +2. **List existing segments.** Use `list-segments` to scan what's there. Look for: + - A segment that already covers the same audience (avoid duplicates) + - Naming conventions already in use (e.g., `beta-testers`, `internal-qa`, `enterprise-accounts`) + - Tags used to organize segments + +### Step 2: Assess the Segment Type + +Before creating, determine the right segment type based on what the user describes. See [Segment Types](references/segment-types.md) for the full guide. + +| Audience description | Segment type | Configuration path | +|---|---|---| +| "All users with an enterprise plan" | Rule-based | `update-segment-rules` → `addRule` with attribute clause | +| "Users whose email ends in @company.com" | Rule-based | `update-segment-rules` → `addRule` with email clause | +| "These specific user keys: [list]" | List-based | `update-segment-targets` → `addIncludedTargets` | +| "Internal testers — I have their keys" | List-based | `update-segment-targets` → `addIncludedTargets` | +| "All enterprise orgs except these two" | Rule-based + exclusions | `update-segment-rules` → `addRule` + `update-segment-targets` → `addExcludedTargets` | + +If in doubt, default to rule-based. It's more flexible and easier to maintain as the audience evolves. + +### Step 3: Create the Segment + +Use `create-segment` with the key, name, environment, and optional tags and description. + +Key notes: +- Segment keys are **immutable** after creation — confirm the key before proceeding. +- Set `unbounded: false` for standard rule-based and smaller list-based segments (15,000 or fewer individual targets). Only set `unbounded: true` for larger list-based segments requiring a BigSegment store. +- Suggest tags based on the segment's purpose, team, or related feature area. + +After creation, the segment is empty — it has no rules and no individual targets. Proceed to Step 4 to configure membership. + +### Step 4: Configure Segment Membership + +Choose the path based on the segment type from Step 2. + +#### Path A: Rule-based — Use `update-segment-rules` + +Add targeting rules that match contexts by attribute. See [Segment Rule Patterns](references/segment-rule-patterns.md) for instruction examples. + +Supported instruction kinds: +- `addRule` — add a new targeting rule with clauses +- `removeRule` — remove a rule by ID +- `addClauses` — add additional clauses to an existing rule +- `removeClauses` — remove clauses from a rule +- `updateClause` — replace a clause entirely +- `addValuesToClause` — append values to a clause's values list +- `removeValuesFromClause` — remove specific values from a clause +- `reorderRules` — change rule evaluation order +- `updateRuleDescription` — update a rule's label +- `updateRuleRolloutAndContextKind` — change percentage and context kind for a percentage-based rule + +Rules within a single rule object are ANDed. To match multiple independent conditions with OR logic, add multiple separate rules. + +#### Path B: List-based — Use `update-segment-targets` + +Add or remove explicit context keys. Supported instruction kinds: +- `addIncludedTargets` — include context keys (requires `contextKind` and `values`) +- `removeIncludedTargets` — remove previously included keys +- `addExcludedTargets` — explicitly exclude context keys from the segment +- `removeExcludedTargets` — remove previously excluded keys + +Always include `contextKind` in the instruction. Defaults to `user` if omitted, but be explicit. + +### Step 5: Wire Into a Flag (Optional) + +If the user wants to use the segment in a feature flag, add a targeting rule to the flag that matches on the segment. + +Use the existing `update-targeting-rules` tool with a `segmentMatch` clause: + +```json +{ + "kind": "addRule", + "clauses": [ + { + "contextKind": "user", + "attribute": "segmentMatch", + "op": "segmentMatch", + "values": [""] + } + ], + "variationId": "", + "description": "Users in segment" +} +``` + +The `variationId` must be the `_id` field from the flag's variations array (retrieved via `get-flag`). Do not use variation index — use the `_id` string. + +For non-user context kinds, set `contextKind` to match the segment's context kind. + +### Step 6: Verify + +After creating and configuring the segment: + +1. **Fetch the segment.** Use `get-segment` to confirm: + - `rulesCount` matches the number of rules added + - `included`/`excluded` counts reflect the target list changes + - `tags` and `description` are correct +2. **If wired to a flag**, use `get-flag` to confirm the rule appears in the flag's targeting rules for the correct environment. +3. **Summarize for the user.** Describe the resulting state in plain language: + - "The `beta-testers` segment in staging now has 1 targeting rule: users whose email ends in `@example.com`. It is wired into the `new-onboarding` flag — beta testers will receive the `true` variation." + +## Edge Cases + +| Situation | Action | +|---|---| +| Segment key already in use | Fetch the existing segment with `get-segment` and show the user what it contains. Ask if they want to configure that segment or create a new one with a different key. | +| User wants to target multiple context kinds in one rule | Create separate rules for each context kind. A single rule's clauses all apply to the same context kind. | +| User has a list of >15,000 context keys | Use `unbounded: true` when creating the segment. Warn the user that BigSegment storage must be configured in the environment for the SDK to evaluate it correctly. | +| Wiring into a flag requires approval | The `update-targeting-rules` call will return `requiresApproval: true` with an `approvalUrl`. Surface this to the user and do not retry the change. | +| User wants the segment in multiple environments | Segments are environment-specific. The workflow must be run once per environment. The segment key and name can be identical across environments, but each is independent. | +| User wants to delete a segment | Deleting segments is out of scope for this skill. Use the LaunchDarkly UI or REST API directly. Caution: deleting a segment that is referenced by flag targeting rules will break those rules. | + +## What NOT to Do + +- Don't create a segment without first checking for duplicates. Step 1 exists for this reason. +- Don't use the `unbounded: true` flag for small lists — it requires a BigSegment store and adds operational complexity without benefit. +- Don't pass variation index numbers to `update-targeting-rules` when wiring a segment into a flag. The API requires the variation `_id` string. Use `get-flag` to look it up. +- Don't add API-level implementation details (segment response shapes, endpoint paths) into conversations with the user. Keep the user experience at the workflow level. +- Don't run `update-segment-rules` and `update-segment-targets` on the same PATCH request — they are separate tools targeting different instruction categories. + +## References + +- [Segment Types](references/segment-types.md) — Rule-based vs list-based decision guide, context kind considerations, size limits +- [Segment Rule Patterns](references/segment-rule-patterns.md) — Semantic patch instruction examples for rules, individual targets, and wiring into flag targeting diff --git a/skills/feature-flags/launchdarkly-segment-create/references/segment-rule-patterns.md b/skills/feature-flags/launchdarkly-segment-create/references/segment-rule-patterns.md new file mode 100644 index 0000000..8b606b3 --- /dev/null +++ b/skills/feature-flags/launchdarkly-segment-create/references/segment-rule-patterns.md @@ -0,0 +1,285 @@ +# Segment Rule Patterns + +Reference for all semantic patch instruction shapes used when configuring segments and wiring them into flags. + +All `update-segment-rules` and `update-segment-targets` calls use semantic patch. Include the header: +``` +Content-Type: application/json; domain-model=launchdarkly.semanticpatch +``` + +The request body takes `instructions` (required), `environmentKey` (required), and `comment` (optional). + +--- + +## update-segment-rules Instructions + +### addRule + +Adds a new targeting rule to the segment. The rule matches contexts that satisfy all its clauses (AND logic between clauses). + +```json +{ + "kind": "addRule", + "clauses": [ + { + "contextKind": "user", + "attribute": "email", + "op": "endsWith", + "negate": false, + "values": ["@company.com"] + } + ], + "description": "Company employees" +} +``` + +To include only a percentage of matching contexts: +```json +{ + "kind": "addRule", + "clauses": [ + { + "contextKind": "user", + "attribute": "plan", + "op": "in", + "negate": false, + "values": ["enterprise"] + } + ], + "weight": 50000, + "rolloutContextKind": "user", + "description": "50% of enterprise users" +} +``` + +Weight is in thousandths of a percent: 50000 = 50%. + +### removeRule + +Removes a rule by its ID. The `ruleId` is the `_id` field from the segment's rules array (returned by `get-segment`). + +```json +{ + "kind": "removeRule", + "ruleId": "a902ef4a-2faf-4eaf-88e1-ecc356708a29" +} +``` + +### addClauses + +Adds additional clauses to an existing rule (narrows the rule's match with AND logic). + +```json +{ + "kind": "addClauses", + "ruleId": "a902ef4a-2faf-4eaf-88e1-ecc356708a29", + "clauses": [ + { + "contextKind": "user", + "attribute": "country", + "op": "in", + "negate": false, + "values": ["US", "CA"] + } + ] +} +``` + +### removeClauses + +Removes specific clauses from a rule by clause IDs. + +```json +{ + "kind": "removeClauses", + "ruleId": "a902ef4a-2faf-4eaf-88e1-ecc356708a29", + "clauseIds": ["10a58772-3121-400f-846b-b8a04e8944ed"] +} +``` + +### updateClause + +Replaces a clause entirely. + +```json +{ + "kind": "updateClause", + "ruleId": "a902ef4a-2faf-4eaf-88e1-ecc356708a29", + "clauseId": "10a58772-3121-400f-846b-b8a04e8944ed", + "clause": { + "contextKind": "user", + "attribute": "plan", + "op": "in", + "negate": false, + "values": ["enterprise", "pro"] + } +} +``` + +### addValuesToClause / removeValuesFromClause + +Add or remove individual values from a clause without replacing it. + +```json +{ + "kind": "addValuesToClause", + "ruleId": "a902ef4a-2faf-4eaf-88e1-ecc356708a29", + "clauseId": "10a58772-3121-400f-846b-b8a04e8944ed", + "values": ["pro"] +} +``` + +```json +{ + "kind": "removeValuesFromClause", + "ruleId": "a902ef4a-2faf-4eaf-88e1-ecc356708a29", + "clauseId": "10a58772-3121-400f-846b-b8a04e8944ed", + "values": ["pro"] +} +``` + +### reorderRules + +Reorders all rules. The array must include every rule ID in the desired evaluation order. + +```json +{ + "kind": "reorderRules", + "ruleIds": [ + "rule-id-2", + "rule-id-1", + "rule-id-3" + ] +} +``` + +### updateRuleDescription + +Updates the display label for a rule. + +```json +{ + "kind": "updateRuleDescription", + "ruleId": "a902ef4a-2faf-4eaf-88e1-ecc356708a29", + "description": "Enterprise users in North America" +} +``` + +### updateRuleRolloutAndContextKind + +Changes the percentage rollout and context kind for a percentage-based rule. + +```json +{ + "kind": "updateRuleRolloutAndContextKind", + "ruleId": "a902ef4a-2faf-4eaf-88e1-ecc356708a29", + "weight": 75000, + "contextKind": "user" +} +``` + +--- + +## update-segment-targets Instructions + +### addIncludedTargets / removeIncludedTargets + +Add or remove context keys from the segment's included list. + +```json +{ + "kind": "addIncludedTargets", + "contextKind": "user", + "values": ["user-key-abc", "user-key-def"] +} +``` + +```json +{ + "kind": "removeIncludedTargets", + "contextKind": "user", + "values": ["user-key-abc"] +} +``` + +### addExcludedTargets / removeExcludedTargets + +Add or remove context keys from the segment's excluded list. Excluded targets are never matched by the segment, even if they would satisfy a targeting rule. + +```json +{ + "kind": "addExcludedTargets", + "contextKind": "user", + "values": ["known-bad-user-key"] +} +``` + +```json +{ + "kind": "removeExcludedTargets", + "contextKind": "user", + "values": ["known-bad-user-key"] +} +``` + +--- + +## Clause Operators Reference + +| Operator | Meaning | Example values | +|---|---|---| +| `in` | Exact match (any value in list) | `["enterprise", "pro"]` | +| `endsWith` | String ends with | `["@company.com"]` | +| `startsWith` | String starts with | `["test-"]` | +| `contains` | String contains substring | `["enterprise"]` | +| `matches` | Regex match | `[".*@company\\.com"]` | +| `lessThan` | Numeric less than | `[100]` | +| `greaterThan` | Numeric greater than | `[0]` | +| `semVerEqual` | Semantic version equals | `["2.0.0"]` | +| `semVerGreaterThan` | Semver greater than | `["1.5.0"]` | +| `semVerLessThan` | Semver less than | `["3.0.0"]` | + +Set `"negate": true` on any clause to invert it (e.g., "email does NOT end with @company.com"). + +--- + +## Wiring a Segment into a Flag + +After creating and configuring the segment, use the existing `update-targeting-rules` tool to add a `segmentMatch` rule to a feature flag. + +### Step 1: Get the flag to find the variation _id + +Use `get-flag` to retrieve the flag's variations array. Each variation has a `_id` field (a UUID string). Use this `_id` — not the variation index — when calling `update-targeting-rules`. + +### Step 2: Add a segmentMatch rule + +```json +{ + "kind": "addRule", + "clauses": [ + { + "contextKind": "user", + "attribute": "segmentMatch", + "op": "segmentMatch", + "values": ["beta-testers"] + } + ], + "variationId": "", + "description": "Users in the beta-testers segment" +} +``` + +The `values` array contains segment keys. Multiple segment keys use OR logic — the rule matches if the context is in any of the listed segments. + +### Step 3: Verify + +Use `get-flag` again to confirm the new rule appears in the environment's targeting rules. + +### Common patterns + +| Goal | segmentMatch clause | +|---|---| +| Target a single segment | `"values": ["beta-testers"]` | +| Target any of multiple segments | `"values": ["beta-testers", "internal-qa"]` | +| Exclude segment members (negate) | Add `"negate": true` to the clause | +| Non-user context kind | Set `contextKind` to the correct kind (e.g., `"organization"`) | diff --git a/skills/feature-flags/launchdarkly-segment-create/references/segment-types.md b/skills/feature-flags/launchdarkly-segment-create/references/segment-types.md new file mode 100644 index 0000000..5e1df6c --- /dev/null +++ b/skills/feature-flags/launchdarkly-segment-create/references/segment-types.md @@ -0,0 +1,85 @@ +# Segment Types + +Reference for choosing the right segment type and understanding the constraints of each. + +## Quick Decision Guide + +| Audience definition | Segment type | Size limit | +|---|---|---| +| Attribute-based (email, plan, country, etc.) | Rule-based | Up to 15,000 individual overrides | +| Explicit list of known context keys | Smaller list-based | Up to 15,000 keys | +| Large list of context keys (>15,000) | Larger list-based (unbounded) | No hard limit; requires BigSegment store | +| Synced from external tool (Amplitude, Twilio, etc.) | Synced segment | Depends on store | + +## Rule-Based Segments + +Rule-based segments match contexts by evaluating attribute conditions. They are the most flexible type and support both targeting rules and individual target overrides. + +**Best for:** +- Audiences defined by a business characteristic ("all enterprise accounts", "users in the EU", "email ends in @company.com") +- Audiences that change naturally as attributes change — no manual maintenance required +- Audiences that combine multiple conditions + +**Constraints:** +- Up to 5,000 targeting rules per segment +- Up to 50,000 values across all rule clauses +- Up to 15,000 individual context targets (included + excluded combined) + +**API creation:** `POST /segments` with no special fields (default is rule-based). + +## Smaller List-Based Segments + +Smaller list-based segments are for when you have a known, explicit list of context keys. They support both individual targets and targeting rules. + +**Best for:** +- Early access programs where you have collected specific user signups +- Internal employee lists ("our 50 internal testers") +- Partner or customer lists maintained manually + +**Constraints:** +- Maximum 15,000 individual context targets +- Same as rule-based for rule support (5,000 rules, 50,000 values) + +**API creation:** Same as rule-based — no special fields needed unless exceeding 15,000 targets. + +## Larger List-Based Segments (Unbounded / BigSegments) + +Larger list-based segments are for audiences exceeding 15,000 entries. LaunchDarkly uses a different implementation ("BigSegments") to maintain performance at scale. + +**Best for:** +- Large customer lists (tens of thousands to millions of entries) +- Bulk imports via CSV + +**Critical requirement:** Server-side SDKs require a persistent store integration (Redis, DynamoDB, etc.) to be configured in each environment before BigSegments work. Without this, the SDK cannot evaluate BigSegment membership and will return the fallback variation. + +**API creation:** Set `unbounded: true` in the POST body. + +**When to flag this:** If a user mentions "we have 50,000 users" or uploads a CSV, prompt them about BigSegment store configuration before proceeding. + +## Context Kinds + +All segment types are context-kind-aware. Each rule clause and individual target instruction applies to one context kind. + +| Situation | What to do | +|---|---| +| Targeting user contexts | Use `contextKind: "user"` (or omit — it defaults to user) | +| Targeting org/account contexts | Use `contextKind: "organization"` (or whatever the project uses) | +| Multiple kinds in one segment | Use separate rules per context kind — a single rule applies to one kind | + +To find what context kinds a project uses, check existing flag targeting rules or ask the user. + +## Segment vs. Flag Targeting Rules + +A common question: when should you define rules in a segment vs. directly in a flag's targeting rules? + +**Use a segment when:** +- The same audience applies to multiple flags +- The audience definition may change (you'd rather update one place) +- The audience has a reusable business meaning ("enterprise customers", "beta testers") + +**Use flag targeting rules directly when:** +- The rule only applies to this one flag +- The rule is a one-off, experiment-specific condition +- You want to keep targeting logic close to the flag + +If a user defines an audience that is already being used — or will be used — in multiple flags, suggest creating a segment and wiring it in, rather than duplicating the rule in each flag.