All skills
launchdarkly avatar

/launchdarkly-flag-drift

@bfbcd29 official

Detect and reconcile drift between a feature flag's in-code SDK fallback default and its LaunchDarkly default rule (fallthrough). Use when a flag's default rule changed, when the user asks to detect flag drift, check whether a hardcoded default still matches LaunchDarkly, sync an in-code default, or open a PR reconciling a fallback value, without removing the flag or its evaluation.

Use this Skill: https://skilld.dev/gh/launchdarkly/agent-skills/launchdarkly-flag-drift

This session only. Nothing lands on disk.

referencessdk-default-patterns.md

≈1.3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

SDK Default Patterns Reference

How to find the fallback default: the value the SDK returns when LaunchDarkly is unreachable, uninitialized, or the flag is unavailable. This is the argument this skill compares against the flag's default rule (fallthrough) and, on drift, the only thing it changes.

How to Spot the Default Argument

In a direct SDK evaluation, the arguments are usually: flag key, context/user, default. The default is almost always the last positional argument. Do not confuse it with the context.

ldClient.<typed>Variation( "<flag-key>", <context>, <DEFAULT> )
                            ^ key         ^ context   ^ the value this skill checks

The default's type should match the flag's variation type (bool flag → boolean default, string flag → string default, etc.). A type mismatch is a bug worth flagging.

Direct Evaluation by Language

JavaScript / TypeScript (Node & client)

ldClient.variation('flag-key', context, defaultValue);
ldClient.boolVariation('flag-key', context, false);      // default = false
ldClient.stringVariation('flag-key', context, 'control'); // default = 'control'
ldClient.numberVariation('flag-key', context, 0);
ldClient.jsonVariation('flag-key', context, {});
ldClient.variationDetail('flag-key', context, defaultValue);

React SDK note: useFlags() reads already-evaluated values and does not expose a per-call default. The default for those flags is set where LDProvider / asyncWithLDProvider is configured (flags bootstrap / default map). Check the provider setup, not the call site.

Python

ld_client.variation('flag-key', context, default_value)
ld_client.bool_variation('flag-key', context, False)
ld_client.string_variation('flag-key', context, 'control')
ld_client.int_variation('flag-key', context, 0)
ld_client.variation_detail('flag-key', context, default_value)

Go

ldClient.BoolVariation("flag-key", context, false)      // default = false
ldClient.StringVariation("flag-key", context, "control")
ldClient.IntVariation("flag-key", context, 0)
ldClient.JSONVariation("flag-key", context, ldvalue.Null())
ldClient.BoolVariationDetail("flag-key", context, false)

Java / Kotlin

ldClient.boolVariation("flag-key", context, false);
ldClient.stringVariation("flag-key", context, "control");
ldClient.intVariation("flag-key", context, 0);
ldClient.jsonValueVariation("flag-key", context, LDValue.ofNull());

Ruby

ld_client.variation('flag-key', context, default_value)
ld_client.bool_variation('flag-key', context, false)
ld_client.string_variation('flag-key', context, 'control')

.NET (C#)

ldClient.BoolVariation("flag-key", context, false);
ldClient.StringVariation("flag-key", context, "control");
ldClient.IntVariation("flag-key", context, 0);
ldClient.JsonVariation("flag-key", context, LdValue.Null);

Abstraction Patterns (where the default is declared once)

Many teams don't call the SDK directly at each site. They declare the default in a central place, then read the flag by key elsewhere. When present, the default in these declarations is the value to check and reconcile.

Wrapper / service method

featureFlags.getBool('flag-key', false);   // default = false
featureFlags.getValue('flag-key', 'control');

Open the wrapper implementation to confirm how the passed value flows into the underlying variation(...) call.

Registry / config map (one default per flag)

// A central flag registry
const flags = {
  'new-checkout-flow': createFlag('new-checkout-flow', /* default */ false),
};
# A config file of flag defaults
feature_flags:
  new-checkout-flow: false

Annotation / struct-tag defaults

Some typed languages encode the default in metadata rather than an argument.

type Flags struct {
    NewCheckoutFlow bool `ld:"new-checkout-flow,false"` // default = false
}
@FeatureFlag(key = "new-checkout-flow", defaultValue = "false")
boolean newCheckoutFlow;

Reconcile the value inside the annotation/tag, not a downstream copy of it.

Generated default files

When flag defaults are compiled into a generated file (e.g. an auto-generated defaults map or typed accessor), do not hand-edit the generated output. Change the source of truth (the registry, annotation, or codegen input) and re-run the project's generation step. Mark requires_generation: true in the summary.

Search Strategy

Search for the flag key with several forms, since codebases mix conventions:

# Exact key, both quote styles
rg "'flag-key'" ; rg '"flag-key"'

# camelCase accessor (kebab keys often surface as camelCase in code)
rg "flagKey"

# Wrapper / registry / config usage and constants
rg "flag-key|flagKey|FLAG_KEY"

# Likely declaration sites
rg "flag-key" -g '*flags*' -g '*.constants.*' -g '*config*'

For each hit, decide whether it is: a direct evaluation (default = last arg), a declaration (default = the declared value), or a read of an already-declared flag (trace back to the declaration). Reconcile at the declaration; read sites need no change.

Source: SKILL.md on GitHub

No alerts2mo3 checks · Risk SAFE
  • Gen Agent Trust Hub2mo

    This skill is an official utility from LaunchDarkly designed to help developers keep their in-code feature flag defaults in sync with their LaunchDarkly configuration. It uses the official LaunchDarkly MCP server to safely fetch flag settings and automates the identification and reconciliation of code-side fallback values. The workflow includes standard safety steps like running existing project tests and linting before proposing changes via a pull request.

  • Socket2mo

    No alerts

  • Snyk2mo

    Risk: LOW · No issues

Signed by skilld at bfbcd29. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 days ago.

Activeupdated 2 months ago
compatibility
Requires the remotely hosted LaunchDarkly MCP server
metadata
{
  "author": "launchdarkly",
  "version": "0.1.0"
}

README badge

README badge for launchdarkly/agent-skills/launchdarkly-flag-drift