
Launchdarkly Flag Cleanup
- 3k installs
- 20 repo stars
- Updated July 27, 2026
- launchdarkly/agent-skills
launchdarkly-flag-cleanup safely removes a feature flag from code using MCP readiness checks and a confirmed forward value.
About
The launchdarkly-flag-cleanup skill removes feature flags from code while preserving production behavior after rollouts complete. Prerequisites require the hosted LaunchDarkly MCP server with check-removal-readiness orchestrating flag config, cross-environment status, dependencies, code references, and expiring targets, plus get-flag for per-environment forward values. Workflow explores codebase references including variation, boolVariation, useFlags, constants, tests, and wrappers before querying LaunchDarkly rather than guessing values. Readiness returns safe, caution, or blocked verdicts; blocked states stop until dependents or active targeting resolve. Forward value selection uses fallthrough.variation when all critical environments are ON with matching rules, or offVariation when uniformly OFF; differing ON states or variations across environments are not safe. Users must confirm a cleanup plan listing forward value, file references, planned edits, readiness verdict, and archive intent before edits. Removal keeps the winning branch, deletes dead code and flag-only imports, and avoids unrelated refactors. Verification runs build, lint, tests, and a final flag key search.
- Requires LaunchDarkly MCP check-removal-readiness before editing code.
- Forward value comes from get-flag fallthrough or offVariation, never guesses.
- Blocked readiness stops when environments disagree on ON state or variation.
- User must confirm cleanup plan before any code modifications begin.
- Remove flag-only imports and dead branches without unrelated refactors.
Launchdarkly Flag Cleanup by the numbers
- 2,985 all-time installs (skills.sh)
- +189 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #11 of 257 Release Management skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
launchdarkly-flag-cleanup capabilities & compatibility
- Capabilities
- codebase flag reference search across sdk patter · mcp readiness orchestration with safe caution bl · forward value determination from per environment · dead branch and import cleanup with minimal diff · pr template guidance and post removal verificati
- Use cases
- refactoring · ci cd
What launchdarkly-flag-cleanup says it does
Never guess the forward value. Query the actual configuration.
Do not proceed with code changes until the user explicitly confirms.
Only remove flag-related code. No unrelated refactors.
npx skills add https://github.com/launchdarkly/agent-skills --skill launchdarkly-flag-cleanupAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 3k |
|---|---|
| repo stars | ★ 20 |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 27, 2026 |
| Repository | launchdarkly/agent-skills ↗ |
How do I remove a finished LaunchDarkly flag from code without changing production behavior?
Safely remove a completed LaunchDarkly feature flag from code by hardcoding the forward variation after MCP readiness checks.
Who is it for?
Teams completing rollouts who need MCP-guided flag deletion with cross-environment safety checks.
Skip if: Skip for creating new flags or discovery audits; use flag-discovery skill first when unsure which flag.
When should I use this skill?
User wants to remove a flag, delete flag references, or hardcode the winning variation after rollout.
What you get
Code hardcoded to the forward variation with dead branches removed and readiness documented in a PR.
- stale flag inventory
- code references removed
By the numbers
- Published at version 1.0.0-experimental
Files
LaunchDarkly Flag Cleanup
You're using a skill that will guide you through safely removing a feature flag from a codebase while preserving production behavior. Your job is to explore the codebase to understand how the flag is used, query LaunchDarkly to determine the correct forward value, remove the flag code cleanly, and verify the result.
If you haven't already identified which flag to clean up, use the flag discovery skill first to audit the landscape and find candidates.
Prerequisites
This skill requires the remotely hosted LaunchDarkly MCP server to be configured in your environment.
Required MCP tools:
check-removal-readiness: detailed safety check (orchestrates flag config, cross-env status, dependencies, code references, and expiring targets in parallel)get-flag: fetch flag configuration for a specific environment
Optional MCP tools:
archive-flag: archive the flag in LaunchDarkly after code removaldelete-flag: permanently delete the flag (irreversible, prefer archive)
Core Principles
1. Safety First: Always preserve current production behavior. 2. LaunchDarkly as Source of Truth: Never guess the forward value. Query the actual configuration. 3. Follow Conventions: Respect existing code style and structure. 4. Minimal Change: Only remove flag-related code. No unrelated refactors.
Workflow
Step 1: Explore the Codebase
Before touching LaunchDarkly or removing code, understand how this flag is used in the codebase.
1. Find all references to the flag key. Search for the flag key string (e.g., new-checkout-flow) across the codebase. Check for:
- Direct SDK evaluation calls (
variation(),boolVariation(),useFlags(), etc.) - Constants/enums that reference the key
- Wrapper/service patterns that abstract the SDK
- Configuration files, tests, and documentation
- See SDK Patterns for the full list of patterns by language
2. Understand the branching. For each reference, identify:
- What code runs when the flag is
true(or variation A)? - What code runs when the flag is
false(or variation B)? - Are there side effects, early returns, or nested conditions?
3. Note the scope. How many files, components, or modules does this flag touch? A flag used in one if block is simpler than one threaded through multiple layers.
Step 2: Run the Removal Readiness Check
Use check-removal-readiness to get a detailed safety assessment. This single tool call orchestrates multiple checks in parallel:
- Flag configuration and targeting state
- Cross-environment status
- Dependent flags (prerequisites)
- Expiring targets
- Code reference statistics
The tool returns a readiness verdict:
`safe`: No blockers or warnings. Proceed with removal.
`caution`: No hard blockers but warnings exist (e.g., code references in other repos, expiring targets scheduled, flag marked as permanent). Present warnings and let the user decide.
`blocked`: Hard blockers prevent safe removal (e.g., dependent flags, actively receiving requests, targeting is on with active rules). Present blockers: the user must resolve them first.
Step 3: Determine the Forward Value
Use get-flag to fetch the flag configuration in each critical environment. The forward value is the variation that replaces the flag in code.
| Scenario | Forward Value |
|---|---|
| All critical envs ON, same fallthrough, no rules/targets | Use fallthrough.variation |
| All critical envs OFF, same offVariation | Use offVariation |
| Critical envs differ in ON/OFF state | NOT SAFE: stop and inform the user |
| Critical envs serve different variations | NOT SAFE: stop and inform the user |
Step 4: Present the Cleanup Plan
Before modifying any code, present a summary to the user and wait for confirmation:
1. The forward value — which variation will be hardcoded and why (based on the flag's current state). 2. All code references found — file paths and line numbers from Step 1. 3. Planned changes — for each reference, describe what will be removed and what will be kept. 4. Readiness verdict — the result from check-removal-readiness (safe, caution, or blocked) and any warnings. 5. LaunchDarkly action — confirm the flag will be archived after code changes are complete.
Do not proceed with code changes until the user explicitly confirms.
Step 5: Remove the Flag from Code
Now execute the removal using what you learned in Step 1.
1. Replace flag evaluations with the forward value.
- Preserve the code branch matching the forward value
- Remove the dead branch entirely
- If the flag value was assigned to a variable, replace the variable with the literal value or inline it
2. Clean up dead code.
- Remove imports, constants, and type definitions that only existed for the flag
- Remove functions, components, or files that only existed for the dead branch
- Check for orphaned exports, hooks, helpers, styles, and test files
- If the repo uses an unused-export tool (Knip, ts-prune, lint rules), run it and remove any flag-related orphans
3. Don't over-clean.
- Only remove code directly related to the flag
- Don't refactor, optimize, or "improve" surrounding code
- Don't change formatting or style of untouched code
Example transformation (boolean flag, forward value = `true`):
// Before
const showNewCheckout = await ldClient.variation('new-checkout-flow', user, false);
if (showNewCheckout) {
return renderNewCheckout();
} else {
return renderOldCheckout();
}
// After
return renderNewCheckout();Step 6: Create Pull Request
Use the template in references/pr-template.md for a structured PR description. The PR should clearly communicate:
- What flag was removed and why
- What the forward value is and why it's correct
- The readiness assessment results (from
check-removal-readiness) - What code was removed and what behavior is preserved
- Whether other repos still reference this flag
Step 7: Verify
Before considering the job done:
1. Code compiles and lints. Run the project's build and lint steps. 2. Tests pass. If the flag was used in tests, the tests should be updated to reflect the hardcoded behavior. 3. No remaining references. Search the codebase one more time for the flag key to make sure nothing was missed. 4. PR is complete. The description covers the readiness assessment, forward value rationale, and any cross-repo coordination needed.
Edge Cases
| Situation | Action |
|---|---|
| Flag not found in LaunchDarkly | Inform user, check for typos in the key |
| Flag already archived | Ask if code cleanup is still needed (flag is gone from LD but code may still reference it) |
| Multiple SDK patterns in codebase | Search all patterns: variation(), boolVariation(), variationDetail(), allFlags(), useFlags(), plus any wrappers |
Dynamic flag keys (flag-${id}) | Warn that automated removal may be incomplete: manual review required |
| Different default values in code vs LD | Flag as inconsistency in the PR description |
| Orphaned exports/files remain after removal | Run unused-export checks and remove dead files |
What NOT to Do
- Don't change code unrelated to flag cleanup.
- Don't refactor or optimize beyond flag removal.
- Don't remove flags still being actively rolled out.
- Don't guess the forward value: always query LaunchDarkly.
After Cleanup
Once the PR is merged and deployed: 1. Archive the flag in LaunchDarkly using archive-flag. Archival is reversible; deletion is not. Always archive first. 2. Notify other teams if check-removal-readiness reported code references in other repositories. 3. If the flag had targeting changes pending, they can be ignored: the flag is being removed.
References
- PR Template: Structured PR description for flag removal
- SDK Patterns: Flag evaluation patterns by language/framework
- Flag Discovery: Find cleanup candidates before using this skill
- Flag Targeting: If you need to change targeting instead of removing
{
"name": "launchdarkly-flag-cleanup",
"description": "Safely automate feature flag cleanup workflows using LaunchDarkly MCP server",
"version": "1.0.0-experimental",
"author": "LaunchDarkly",
"repository": "https://github.com/launchdarkly/ai-tooling",
"skills": ["./"],
"tags": [
"launchdarkly",
"feature-flags",
"feature-management",
"stale-flags",
"tech-debt",
"cleanup",
"code-removal",
"devops",
"mcp"
],
"requirements": {
"mcp-servers": ["@launchdarkly/mcp-server"]
}
}
LaunchDarkly Flag Cleanup Skill
An Agent Skill for safely automating feature flag cleanup workflows using LaunchDarkly as the source of truth.
Overview
This skill teaches agents how to:
- Determine if a feature flag is ready for removal
- Calculate the correct forward value to preserve production behavior
- Safely remove flag references from code
- Create well-documented pull requests
Installation (Local)
For now, install by placing this skill directory where your agent client loads skills.
Examples:
- Generic: copy
skills/feature-flags/launchdarkly-flag-cleanup/into your client's skills path
Prerequisites
This skill requires the remotely hosted LaunchDarkly MCP server to be configured in your environment. The remote server provides higher-level, agent-optimized tools that orchestrate multiple API calls and return pruned, actionable responses.
Refer to your LaunchDarkly account settings for instructions on connecting to the remotely hosted MCP server.
Usage
Once installed, the skill activates automatically when you ask about flag cleanup:
Remove the `new-checkout-flow` feature flagIs the `dark-mode` flag ready to be cleaned up?Clean up stale feature flags in this codebaseStructure
launchdarkly-flag-cleanup/
├── SKILL.md
├── marketplace.json
├── README.md
└── references/
├── pr-template.md
└── sdk-patterns.mdRelated
License
Apache-2.0
PR Template for Flag Removal
Use this template when creating pull requests for flag cleanup.
## Flag Removal: `{flag-key}`
### Removal Summary
- **Forward Value**: `{variation value being preserved}`
- **Critical Environments**: {list environments}
- **Status**: ✅ Ready for removal / ⚠️ Proceed with caution / ❌ Not ready
### Removal Readiness Assessment
**Configuration Analysis:**
| Environment | State | Serving | Rules | Targets |
|-------------|-------|---------|-------|---------|
| production | ON/OFF | `{value}` | none/present | none/count |
| {other env} | ON/OFF | `{value}` | none/present | none/count |
**Lifecycle Status:**
| Environment | Status | Evaluations (7d) |
|-------------|--------|------------------|
| production | launched/active/inactive/new | {count} |
| {other env} | launched/active/inactive/new | {count} |
**Code References:**
- Repositories with references: `{count}`
- This PR addresses: `{current repo}`
- Other repos requiring cleanup: `{list if any}`
### Changes Made
- Removed flag evaluation calls: `{count}` occurrences
- Files modified: `{list files}`
- Preserved behavior: `{describe what code now does}`
- Cleaned up: `{list dead code removed}`
### Risk Assessment
{Explain why this change is safe. Address:}
- Why the forward value is correct
- Any edge cases considered
- Impact on other environments (if any)
### Reviewer Checklist
- [ ] Forward value matches production behavior
- [ ] All flag references removed
- [ ] No unrelated changes included
- [ ] Tests pass (if applicable)
- [ ] Dead code properly removed
### Post-Merge Actions
- [ ] Archive flag in LaunchDarkly (after deployment confirmed)
- [ ] Notify other teams if they have code referencesExample: Ready for Removal
## Flag Removal: `new-checkout-flow`
### Removal Summary
- **Forward Value**: `true`
- **Critical Environments**: production, prod-eu
- **Status**: ✅ Ready for removal
### Removal Readiness Assessment
**Configuration Analysis:**
| Environment | State | Serving | Rules | Targets |
|-------------|-------|---------|-------|---------|
| production | ON | `true` | none | none |
| prod-eu | ON | `true` | none | none |
**Lifecycle Status:**
| Environment | Status | Evaluations (7d) |
|-------------|--------|------------------|
| production | launched | 142,531 |
| prod-eu | launched | 89,203 |
**Code References:**
- Repositories with references: 2
- This PR addresses: `checkout-service`
- Other repos requiring cleanup: `mobile-app`
### Changes Made
- Removed flag evaluation calls: 3 occurrences
- Files modified: `CheckoutController.ts`, `CheckoutService.ts`, `checkout.test.ts`
- Preserved behavior: Always renders new checkout experience
- Cleaned up: Removed `renderOldCheckout()` function and related imports
### Risk Assessment
This change is safe because:
- Both production environments serve `true` to 100% of traffic
- Flag has been at 100% for 47 days with no issues
- No targeting rules or individual overrides exist
- The new checkout flow has been fully validated
### Post-Merge Actions
- [ ] Archive flag in LaunchDarkly (after deployment confirmed)
- [ ] Create follow-up ticket for mobile-app cleanupExample: Proceed with Caution
## Flag Removal: `legacy-api-endpoint`
### Removal Summary
- **Forward Value**: `false`
- **Critical Environments**: production
- **Status**: ⚠️ Proceed with caution
### Removal Readiness Assessment
**Configuration Analysis:**
| Environment | State | Serving | Rules | Targets |
|-------------|-------|---------|-------|---------|
| production | OFF | `false` | none | none |
**Lifecycle Status:**
| Environment | Status | Evaluations (7d) |
|-------------|--------|------------------|
| production | inactive | 0 |
⚠️ **Warning**: Zero evaluations in the last 7 days. This flag may be:
- Dead code that's safe to remove
- Used by a batch job or infrequent process
- Referenced but never called
**Recommendation**: Verify with the team that this code path is truly unused before merging.SDK Patterns Reference
Common flag evaluation patterns by SDK and language. Search for these patterns when finding flag references.
JavaScript/TypeScript (Node.js)
// Standard evaluation
ldClient.variation('flag-key', context, defaultValue);
ldClient.boolVariation('flag-key', context, false);
ldClient.stringVariation('flag-key', context, 'default');
ldClient.numberVariation('flag-key', context, 0);
ldClient.jsonVariation('flag-key', context, {});
// With details (includes reason)
ldClient.variationDetail('flag-key', context, defaultValue);
ldClient.boolVariationDetail('flag-key', context, false);
// All flags
ldClient.allFlagsState(context);JavaScript/TypeScript (Browser/React)
// React SDK hooks
const { flags } = useFlags();
const flagValue = flags['flag-key'];
const flagValue = flags.flagKey; // camelCase access
// useLDClient hook
const ldClient = useLDClient();
ldClient.variation('flag-key', defaultValue);
// withLDConsumer HOC
this.props.flags['flag-key']
this.props.ldClient.variation('flag-key', defaultValue);
// Direct client usage
LDClient.variation('flag-key', defaultValue);Python
# Standard evaluation
ld_client.variation('flag-key', context, default_value)
ld_client.bool_variation('flag-key', context, False)
ld_client.string_variation('flag-key', context, 'default')
ld_client.int_variation('flag-key', context, 0)
ld_client.float_variation('flag-key', context, 0.0)
ld_client.json_variation('flag-key', context, {})
# With details
ld_client.variation_detail('flag-key', context, default_value)
ld_client.bool_variation_detail('flag-key', context, False)
# All flags
ld_client.all_flags_state(context)Go
// Standard evaluation
ldClient.BoolVariation("flag-key", context, false)
ldClient.StringVariation("flag-key", context, "default")
ldClient.IntVariation("flag-key", context, 0)
ldClient.Float64Variation("flag-key", context, 0.0)
ldClient.JSONVariation("flag-key", context, ldvalue.Null())
// With details
ldClient.BoolVariationDetail("flag-key", context, false)
ldClient.StringVariationDetail("flag-key", context, "default")
// All flags
ldClient.AllFlagsState(context)Java/Kotlin
// Standard evaluation
ldClient.boolVariation("flag-key", context, false);
ldClient.stringVariation("flag-key", context, "default");
ldClient.intVariation("flag-key", context, 0);
ldClient.doubleVariation("flag-key", context, 0.0);
ldClient.jsonValueVariation("flag-key", context, LDValue.ofNull());
// With details
ldClient.boolVariationDetail("flag-key", context, false);
ldClient.stringVariationDetail("flag-key", context, "default");
// All flags
ldClient.allFlagsState(context);Ruby
# Standard evaluation
ld_client.variation('flag-key', context, default_value)
ld_client.bool_variation('flag-key', context, false)
ld_client.string_variation('flag-key', context, 'default')
ld_client.number_variation('flag-key', context, 0)
ld_client.json_variation('flag-key', context, {})
# With details
ld_client.variation_detail('flag-key', context, default_value)
# All flags
ld_client.all_flags_state(context).NET (C#)
// Standard evaluation
ldClient.BoolVariation("flag-key", context, false);
ldClient.StringVariation("flag-key", context, "default");
ldClient.IntVariation("flag-key", context, 0);
ldClient.FloatVariation("flag-key", context, 0.0f);
ldClient.DoubleVariation("flag-key", context, 0.0);
ldClient.JsonVariation("flag-key", context, LdValue.Null);
// With details
ldClient.BoolVariationDetail("flag-key", context, false);
ldClient.StringVariationDetail("flag-key", context, "default");
// All flags
ldClient.AllFlagsState(context);Common Wrapper Patterns
Many teams create abstraction layers. Search for these patterns too:
// Service wrappers
featureFlagService.isEnabled('flag-key');
featureFlagService.getValue('flag-key');
featureFlagService.getFlag('flag-key');
FeatureFlags.isEnabled('flag-key');
// Constants/enums
FLAGS.NEW_CHECKOUT_FLOW
FeatureFlag.NEW_CHECKOUT_FLOW
FEATURE_FLAGS['flag-key']
// Decorator patterns (Python/Java)
@feature_flag('flag-key')
@FeatureFlag("flag-key")
// Configuration files
feature_flags:
flag-key: trueSearch Strategies
When searching for flag references, use multiple patterns:
# Exact string match
grep -r "'flag-key'" .
grep -r '"flag-key"' .
# Case variations (kebab-case to camelCase)
grep -r "flagKey" .
# Partial matches for wrapper usage
grep -r "flag-key\|flagKey\|FLAG_KEY" .
# Check constants files
grep -r "flag-key" . --include="*.constants.*"
grep -r "flag-key" . --include="*flags*"Removal Patterns
Boolean flag (forward value = true)
// Before
if (ldClient.variation('flag-key', user, false)) {
doNewThing();
} else {
doOldThing();
}
// After
doNewThing();Boolean flag (forward value = false)
// Before
if (ldClient.variation('flag-key', user, false)) {
doNewThing();
} else {
doOldThing();
}
// After
doOldThing();String/multivariate flag
// Before
const variant = ldClient.variation('flag-key', user, 'control');
switch (variant) {
case 'new':
return renderNew();
case 'experimental':
return renderExperimental();
default:
return renderControl();
}
// After (forward value = 'new')
return renderNew();Early return pattern
// Before
const enabled = ldClient.variation('flag-key', user, false);
if (!enabled) {
return null;
}
return <NewFeature />;
// After (forward value = true)
return <NewFeature />;
// After (forward value = false)
return null;Related skills
Forks & variants (1)
Launchdarkly Flag Cleanup has 1 known copy in the catalog totaling 483 installs. They canonicalize to this original listing.
- launchdarkly - 483 installs
FAQ
Which MCP tool checks if removal is safe?
Call check-removal-readiness for safe, caution, or blocked verdicts across environments and dependencies.
When is removal not safe?
When critical environments differ in ON/OFF state or serve different variations for the same flag.
Must I confirm before editing code?
Yes. Present forward value, references, planned edits, and readiness verdict, then wait for explicit confirmation.