Agent skill
openfeature-eng
Implement OpenFeature feature flags in software projects. Use when adding feature flags with OpenFeature SDKs, configuring providers, setting up evaluation context, or integrating the OpenFeature MCP Server.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/openfeature-eng
SKILL.md
OpenFeature Implementation
Guide for implementing OpenFeature - the open standard for feature flag management - across server and client applications.
When to Use This Skill
- Adding feature flags to a new or existing project
- Implementing OpenFeature Server SDKs (Go, Java, .NET, Node.js, PHP, Python, Ruby, Rust, Dart)
- Implementing OpenFeature Client SDKs (JavaScript, React, Angular, Kotlin, iOS/Swift)
- Configuring feature flag providers (flagd, LaunchDarkly, Split, etc.)
- Setting up evaluation context for targeting
- Using the OpenFeature MCP Server
This skill does NOT cover:
- Creating custom OpenFeature providers (see provider development docs)
- Vendor-specific flag management UIs
- Feature flag strategy/design patterns
Core Concepts
OpenFeature Architecture
┌─────────────────────────────────────────────────────────────┐
│ Application Code │
│ client.getBooleanValue("feature-x", false, context) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ OpenFeature SDK │
│ - Evaluation API │
│ - Hooks (before/after/error/finally) │
│ - Event handling │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Provider │
│ flagd | LaunchDarkly | Split | CloudBees | In-Memory │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Flag Management │
│ Flag definitions, rules, segments, rollouts │
└─────────────────────────────────────────────────────────────┘
Key Terms
| Term | Description |
|---|---|
| Provider | Backend that evaluates flags (flagd, LaunchDarkly, etc.) |
| Client | SDK instance for evaluating flags |
| Context | User/request attributes for targeting |
| Hook | Lifecycle callbacks for logging, metrics |
| Flag | Feature toggle with key, type, and default value |
Server SDK Implementations
Go
go get github.com/open-feature/go-sdk
package main
import (
"context"
"github.com/open-feature/go-sdk/openfeature"
"github.com/open-feature/go-sdk-contrib/providers/flagd/pkg"
)
func main() {
// Set up provider
provider := flagd.NewProvider()
openfeature.SetProvider(provider)
// Get client
client := openfeature.NewClient("my-app")
// Evaluation context
ctx := openfeature.NewEvaluationContext(
"user-123",
map[string]interface{}{
"email": "user@example.com",
"tier": "premium",
},
)
// Evaluate flags
enabled, _ := client.BooleanValue(
context.Background(),
"new-feature",
false,
ctx,
)
if enabled {
// New feature code
}
}
Java
<dependency>
<groupId>dev.openfeature</groupId>
<artifactId>sdk</artifactId>
<version>1.7.0</version>
</dependency>
import dev.openfeature.sdk.*;
import dev.openfeature.contrib.providers.flagd.FlagdProvider;
public class FeatureFlags {
public static void main(String[] args) {
// Set provider
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
api.setProvider(new FlagdProvider());
// Get client
Client client = api.getClient("my-app");
// Evaluation context
EvaluationContext ctx = new ImmutableContext("user-123",
Map.of(
"email", new Value("user@example.com"),
"tier", new Value("premium")
)
);
// Evaluate flags
boolean enabled = client.getBooleanValue("new-feature", false, ctx);
if (enabled) {
// New feature code
}
}
}
.NET
dotnet add package OpenFeature
dotnet add package OpenFeature.Contrib.Providers.Flagd
using OpenFeature;
using OpenFeature.Contrib.Providers.Flagd;
// Set provider
var provider = new FlagdProvider();
await Api.Instance.SetProviderAsync(provider);
// Get client
var client = Api.Instance.GetClient("my-app");
// Evaluation context
var context = EvaluationContext.Builder()
.SetTargetingKey("user-123")
.Set("email", "user@example.com")
.Set("tier", "premium")
.Build();
// Evaluate flags
var enabled = await client.GetBooleanValueAsync("new-feature", false, context);
if (enabled)
{
// New feature code
}
Node.js / TypeScript
npm install @openfeature/server-sdk @openfeature/flagd-provider
import { OpenFeature } from '@openfeature/server-sdk';
import { FlagdProvider } from '@openfeature/flagd-provider';
// Set provider
await OpenFeature.setProviderAndWait(new FlagdProvider());
// Get client
const client = OpenFeature.getClient('my-app');
// Evaluation context
const context = {
targetingKey: 'user-123',
email: 'user@example.com',
tier: 'premium',
};
// Evaluate flags
const enabled = await client.getBooleanValue('new-feature', false, context);
if (enabled) {
// New feature code
}
NestJS Integration
npm install @openfeature/server-sdk @openfeature/nestjs-sdk @openfeature/flagd-provider
// app.module.ts
import { Module } from '@nestjs/common';
import { OpenFeatureModule } from '@openfeature/nestjs-sdk';
import { FlagdProvider } from '@openfeature/flagd-provider';
@Module({
imports: [
OpenFeatureModule.forRoot({
defaultProvider: new FlagdProvider(),
}),
],
})
export class AppModule {}
// feature.service.ts
import { Injectable } from '@nestjs/common';
import {
OpenFeatureClient,
BooleanFeatureFlag
} from '@openfeature/nestjs-sdk';
import { Client } from '@openfeature/server-sdk';
@Injectable()
export class FeatureService {
constructor(
@OpenFeatureClient() private client: Client,
) {}
@BooleanFeatureFlag({
flagKey: 'new-feature',
defaultValue: false,
})
async isNewFeatureEnabled(): Promise<boolean> {
return this.client.getBooleanValue('new-feature', false);
}
}
Python
pip install openfeature-sdk openfeature-provider-flagd
from openfeature import api
from openfeature.evaluation_context import EvaluationContext
from openfeature.contrib.provider.flagd import FlagdProvider
# Set provider
api.set_provider(FlagdProvider())
# Get client
client = api.get_client("my-app")
# Evaluation context
context = EvaluationContext(
targeting_key="user-123",
attributes={
"email": "user@example.com",
"tier": "premium",
}
)
# Evaluate flags
enabled = client.get_boolean_value("new-feature", False, context)
if enabled:
# New feature code
pass
Ruby
gem install openfeature-sdk openfeature-flagd-provider
require 'openfeature/sdk'
require 'openfeature/flagd/provider'
# Set provider
OpenFeature::SDK.configure do |config|
config.set_provider(OpenFeature::Flagd::Provider.new)
end
# Get client
client = OpenFeature::SDK.build_client(name: 'my-app')
# Evaluation context
context = OpenFeature::SDK::EvaluationContext.new(
targeting_key: 'user-123',
email: 'user@example.com',
tier: 'premium'
)
# Evaluate flags
enabled = client.fetch_boolean_value(
flag_key: 'new-feature',
default_value: false,
evaluation_context: context
)
if enabled
# New feature code
end
Rust
[dependencies]
open-feature = "0.2"
use open_feature::{
provider::NoOpProvider,
EvaluationContext, OpenFeature,
};
#[tokio::main]
async fn main() {
// Set provider
let mut api = OpenFeature::singleton_mut().await;
api.set_provider(NoOpProvider::default()).await;
// Get client
let client = api.create_client();
// Evaluation context
let context = EvaluationContext::default()
.with_targeting_key("user-123")
.with_custom_field("email", "user@example.com")
.with_custom_field("tier", "premium");
// Evaluate flags
let enabled = client
.get_bool_value("new-feature", Some(&context), None)
.await
.unwrap_or(false);
if enabled {
// New feature code
}
}
Dart
dependencies:
openfeature_dart_sdk: ^0.1.0
import 'package:openfeature_dart_sdk/openfeature_dart_sdk.dart';
void main() async {
// Set provider
final api = OpenFeatureAPI.instance;
await api.setProvider(InMemoryProvider());
// Get client
final client = api.getClient('my-app');
// Evaluation context
final context = EvaluationContext(
targetingKey: 'user-123',
attributes: {
'email': 'user@example.com',
'tier': 'premium',
},
);
// Evaluate flags
final enabled = await client.getBooleanValue(
'new-feature',
defaultValue: false,
context: context,
);
if (enabled) {
// New feature code
}
}
PHP
composer require open-feature/sdk open-feature/flagd-provider
<?php
use OpenFeature\OpenFeatureAPI;
use OpenFeature\Providers\Flagd\FlagdProvider;
use OpenFeature\implementation\flags\EvaluationContext;
// Set provider
$api = OpenFeatureAPI::getInstance();
$api->setProvider(new FlagdProvider());
// Get client
$client = $api->getClient('my-app');
// Evaluation context
$context = new EvaluationContext(
'user-123',
[
'email' => 'user@example.com',
'tier' => 'premium',
]
);
// Evaluate flags
$enabled = $client->getBooleanValue('new-feature', false, $context);
if ($enabled) {
// New feature code
}
Client SDK Implementations
React
npm install @openfeature/react-sdk @openfeature/web-sdk @openfeature/flagd-web-provider
// App.tsx
import { OpenFeatureProvider, useBooleanFlagValue } from '@openfeature/react-sdk';
import { FlagdWebProvider } from '@openfeature/flagd-web-provider';
const provider = new FlagdWebProvider({
host: 'localhost',
port: 8013,
});
function App() {
return (
<OpenFeatureProvider provider={provider}>
<FeatureComponent />
</OpenFeatureProvider>
);
}
function FeatureComponent() {
const enabled = useBooleanFlagValue('new-feature', false);
return enabled ? <NewFeature /> : <OldFeature />;
}
// With evaluation context
import { useOpenFeatureClient } from '@openfeature/react-sdk';
function UserFeature({ userId }: { userId: string }) {
const client = useOpenFeatureClient();
const enabled = useBooleanFlagValue('premium-feature', false, {
targetingKey: userId,
tier: 'premium',
});
return enabled ? <PremiumFeature /> : <StandardFeature />;
}
Angular
npm install @openfeature/angular-sdk @openfeature/web-sdk
// app.module.ts
import { NgModule } from '@angular/core';
import { OpenFeatureModule } from '@openfeature/angular-sdk';
import { InMemoryProvider } from '@openfeature/web-sdk';
@NgModule({
imports: [
OpenFeatureModule.forRoot({
provider: new InMemoryProvider({
'new-feature': {
disabled: false,
variants: { on: true, off: false },
defaultVariant: 'on'
},
}),
}),
],
})
export class AppModule {}
// feature.component.ts
import { Component } from '@angular/core';
import { BooleanFeatureFlag } from '@openfeature/angular-sdk';
@Component({
selector: 'app-feature',
template: `
<div *ngIf="isEnabled$ | async">
New Feature Content
</div>
`,
})
export class FeatureComponent {
@BooleanFeatureFlag({ flagKey: 'new-feature', defaultValue: false })
isEnabled$!: Observable<boolean>;
}
Kotlin (Android)
// build.gradle.kts
dependencies {
implementation("dev.openfeature:android-sdk:0.3.0")
}
import dev.openfeature.sdk.OpenFeatureAPI
import dev.openfeature.sdk.EvaluationContext
import dev.openfeature.contrib.providers.flagd.FlagdProvider
class FeatureFlags(context: Context) {
private val client: Client
init {
// Set provider
val api = OpenFeatureAPI.getInstance()
api.setProvider(FlagdProvider())
client = api.getClient("my-app")
}
suspend fun isNewFeatureEnabled(userId: String): Boolean {
val context = EvaluationContext(
targetingKey = userId,
attributes = mapOf(
"platform" to "android",
"version" to BuildConfig.VERSION_NAME
)
)
return client.getBooleanValue("new-feature", false, context)
}
}
iOS / Swift
// Package.swift
dependencies: [
.package(url: "https://github.com/open-feature/swift-sdk.git", from: "0.1.0")
]
import OpenFeature
class FeatureFlags {
private let client: Client
init() {
// Set provider
let api = OpenFeatureAPI.shared
api.setProvider(provider: InMemoryProvider())
client = api.getClient(name: "my-app")
}
func isNewFeatureEnabled(userId: String) async -> Bool {
let context = MutableContext(
targetingKey: userId,
structure: MutableStructure(
attributes: [
"platform": .string("ios"),
"version": .string(Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "")
]
)
)
return await client.getBooleanValue(
key: "new-feature",
defaultValue: false,
context: context
)
}
}
Provider Configuration
flagd (Open Source)
# flagd-config.yaml
flags:
new-feature:
state: ENABLED
variants:
"on": true
"off": false
defaultVariant: "off"
targeting:
if:
- in:
- var: tier
- ["premium", "enterprise"]
- "on"
- "off"
# Run flagd
docker run -p 8013:8013 -v ./flagd-config.yaml:/config.yaml \
ghcr.io/open-feature/flagd:latest start --uri file:/config.yaml
In-Memory Provider (Testing)
import { InMemoryProvider } from '@openfeature/server-sdk';
const flags = {
'new-feature': {
disabled: false,
variants: { on: true, off: false },
defaultVariant: 'on',
},
'feature-limit': {
disabled: false,
variants: { low: 10, medium: 50, high: 100 },
defaultVariant: 'medium',
},
};
await OpenFeature.setProviderAndWait(new InMemoryProvider(flags));
OpenFeature MCP Server
The OpenFeature MCP Server enables flag evaluation through Claude.
Installation
npx @openfeature/mcp-server
Configuration
{
"mcpServers": {
"openfeature": {
"command": "npx",
"args": ["@openfeature/mcp-server"],
"env": {
"FLAGD_HOST": "localhost",
"FLAGD_PORT": "8013"
}
}
}
}
Usage
The MCP server provides tools for:
- Evaluating feature flags
- Listing available flags
- Getting flag metadata
Hooks
Logging Hook
import { Hook, HookContext, EvaluationDetails } from '@openfeature/server-sdk';
const loggingHook: Hook = {
before: (hookContext: HookContext) => {
console.log(`Evaluating flag: ${hookContext.flagKey}`);
},
after: (hookContext: HookContext, details: EvaluationDetails<any>) => {
console.log(`Flag ${hookContext.flagKey} = ${details.value}`);
},
error: (hookContext: HookContext, error: Error) => {
console.error(`Error evaluating ${hookContext.flagKey}:`, error);
},
};
client.addHooks(loggingHook);
Metrics Hook
const metricsHook: Hook = {
after: (hookContext, details) => {
metrics.increment('feature_flag.evaluation', {
flag: hookContext.flagKey,
variant: details.variant,
reason: details.reason,
});
},
};
Testing
Unit Testing with Mocks
import { OpenFeature, InMemoryProvider } from '@openfeature/server-sdk';
describe('Feature Tests', () => {
beforeEach(async () => {
await OpenFeature.setProviderAndWait(
new InMemoryProvider({
'new-feature': {
disabled: false,
variants: { on: true, off: false },
defaultVariant: 'on',
},
})
);
});
it('should show new feature when enabled', async () => {
const client = OpenFeature.getClient();
const enabled = await client.getBooleanValue('new-feature', false);
expect(enabled).toBe(true);
});
});
Best Practices
- Set default values defensively - Always provide sensible defaults
- Use targeting keys - Enable user-level targeting and consistency
- Add evaluation context - Include relevant attributes for targeting
- Implement hooks - Add logging and metrics for observability
- Clean up flags - Remove flags after features are fully rolled out
- Use typed values - Prefer specific value types over strings
- Test both paths - Test feature on and off states
References
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?