Feature Flags

SkillAI & models

Feature flag management. LaunchDarkly, Unleash, Flagsmith, and custom implementations. Gradual rollouts, A/B testing, kill switches, and flag lifecycle management.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Feature Flags skill

What this skill tells your AI

The instructions your AI receives, as published by claude-dev-suite/claude-dev-suite in skills/best-practices/feature-flags/SKILL.md and read by ahel’s review.

LaunchDarkly

import * as LaunchDarkly from '@launchdarkly/node-server-sdk';

const client = LaunchDarkly.init(process.env.LD_SDK_KEY!);
await client.waitForInitialization();

// Evaluate flag
const showNewUI = await client.variation('new-dashboard-ui', {
  key: user.id,
  email: user.email,
  custom: { plan: user.plan },
}, false); // default value

if (showNewUI) {
  renderNewDashboard();
} else {
  renderLegacyDashboard();
}

React SDK

import { useFlags, withLDProvider } from 'launchdarkly-react-client-sdk';

function Dashboard() {
  const { newDashboardUi, maxUploadSize } = useFlags();

  return newDashboardUi ? <NewDashboard maxUpload={maxUploadSize} /> : <LegacyDashboard />;
}

// Wrap app
export default withLDProvider({
  clientSideID: process.env.NEXT_PUBLIC_LD_CLIENT_ID!,
  context: { kind: 'user', key: user.id, email: user.email },
})(App);

Unleash (self-hosted)

import { initialize } from 'unleash-client';

const unleash = initialize({
  url: 'https://unleash.example.com/api',
  appName: 'my-app',
  customHeaders: { Authorization: process.env.UNLEASH_API_KEY! },
});

if (unleash.isEnabled('new-checkout', { userId: user.id })) {
  // New checkout flow
}

Custom Implementation (simple)

interface FeatureFlags {
  [key: string]: {
    enabled: boolean;
    rolloutPercentage?: number;
    allowedUsers?: string[];
  };
}

class FlagService {
  constructor(private flags: FeatureFlags) {}

  isEnabled(flag: string, userId?: string): boolean {
    const config = this.flags[flag];
    if (!config?.enabled) return false;
    if (config.allowedUsers?.includes(userId!)) return true;
    if (config.rolloutPercentage != null && userId) {
      const hash = simpleHash(userId + flag) % 100;
      return hash < config.rolloutPercentage;
    }
    return config.enabled;
  }
}

Flag Types

TypePurposeExample
BooleanOn/off togglenew-ui-enabled
Percentage rolloutGradual release10% → 50% → 100%
User targetingSpecific usersBeta testers, internal
MultivariateA/B/C testingcheckout-variant: "A"
Kill switchEmergency disablepayments-enabled

Anti-Patterns

Anti-PatternFix
Flags that live foreverSet expiration, clean up after full rollout
Flag checks deep in codeCheck at entry points, pass result down
No default valuesAlways provide sensible defaults
Testing only flagged-on pathTest both paths in CI
Flags in tight loopsCache flag evaluation result

Production Checklist

  • Default values for all flags (graceful degradation)
  • Flag naming convention (feature-name-action)
  • Cleanup process for fully-rolled-out flags
  • Monitoring: flag evaluation metrics
  • Testing both flag states in CI
  • Audit log of flag changes

Signals

GitHub stars
33
Forks
6
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
feature-flags-claude-dev-suite
Source
github.com/claude-dev-suite/claude-dev-suite