Skip to main content

Feature Flag System

Overview​

Bike4Mind uses a two-tier feature flag system that allows for controlled rollout of experimental features. This approach ensures that new features can be tested by specific users while keeping them disabled by default for others. The feature flag system consists of:

  1. Server-level settings (Admin Settings): Control global availability of features
  2. User-level settings (User Preferences): Allow individual users to opt-in to enabled features

This documentation covers the architecture, implementation details, and guides for working with feature flags in Bike4Mind.

Architecture​

Server-Side Settings​

Server-side feature flags are defined as admin settings in b4m-core/packages/core/common/schemas/settings.ts. These settings determine whether a feature is globally available for any user to enable.

// In settingsMap
EnableQuestMaster: makeBooleanSetting({
key: 'EnableQuestMaster',
name: 'Enable Quest Master',
defaultValue: false,
description: 'Whether to enable the Quest Master feature.',
category: 'Experimental',
group: API_SERVICE_GROUPS.EXPERIMENTAL.id,
order: 1,
}),

All experimental features are grouped under the EXPERIMENTAL service group:

EXPERIMENTAL: {
id: 'experimentalService',
name: 'Experimental Features',
description: 'Experimental and beta feature settings',
icon: 'Science',
settings: [
{ key: 'EnableQuestMaster', order: 1 },
{ key: 'EnableMementos', order: 2 },
{ key: 'MementoMaxTotalChars', order: 3 },
{ key: 'EnableArtifacts', order: 4 },
],
},

Client-Side Settings​

Client-side feature flags are stored in the user's browser localStorage under the user-settings key. These settings represent the user's preference for each experimental feature.

Default settings are defined in packages/client/app/contexts/UserSettingsContext.tsx:

const defaultSettings: UserSettings = {
// Other settings...
experimentalFeatures: {
enableQuestMaster: false,
enableMementos: false,
enableArtifacts: false,
enableOllama: false,
},
};

Feature Activation Flow​

For a feature to be activated for a user:

  1. The feature must be enabled at the server level (admin setting)
  2. The user must opt-in by enabling the feature in their settings

This dual-layer approach provides fine-grained control over feature rollouts.

Current Experimental Features​

QuestMaster​

Description: An AI model-agnostic agentic system that creates structured plans for user queries.

Implementation:

  • Server flag: EnableQuestMaster
  • Client flag: enableQuestMaster
  • Main implementation: QuestMasterFeature class in ChatCompletionFeatures.ts

When enabled, QuestMaster processes user messages to create a structured plan before generating a response, providing more contextual and multi-step answers.

Mementos​

Description: A system that saves and revisits important moments from learning sessions with AI-generated summaries.

Implementation:

  • Server flag: EnableMementos
  • Client flag: enableMementos
  • Main implementation: MementoFeature class in ChatCompletionFeatures.ts

When enabled, the Mementos feature automatically identifies and stores significant conversational moments, which are then used to provide context in future conversations.

Artifacts​

Description: A system for generating and collecting learning artifacts like code samples, diagrams, and practice exercises.

Implementation:

  • Server flag: EnableArtifacts
  • Client flag: enableArtifacts
  • Types defined in: ArtifactTypes.ts

Artifacts represent rich content types (diagrams, code, etc.) that can be generated during conversations and stored for reference.

Using Feature Flags in Code​

Checking Feature Enablement​

To check if a feature is enabled in the backend:

// In ChatCompletion.ts
const adminSettingsEnableQuestMaster = getSettingsValue('EnableQuestMaster', adminSettings);

if (enableQuestMaster && adminSettingsEnableQuestMaster) {
// Feature is enabled at both server and user level
this.features.set('questMaster', new QuestMasterFeature(this));
}

To check if a feature is enabled in the frontend:

// In a React component
const { settings } = useUserSettings();
const isQuestMasterEnabled = settings.experimentalFeatures?.enableQuestMaster;

if (isQuestMasterEnabled) {
// Use the feature
}

Passing Feature Flags to API​

When sending chat messages, experimental feature flags are passed to the API:

// In sessionsAPICalls.ts
const response = await api.post(`/api/sessions/${sessionId}/chat`, {
...message,
enableQuestMaster: experimentalFeatures?.enableQuestMaster,
enableMementos: experimentalFeatures?.enableMementos,
enableArtifacts: experimentalFeatures?.enableArtifacts,
});

Adding Feature Flags to LLM Context​

Feature flags are propagated to the LLM context in LLMContext.tsx:

useEffect(() => {
setState(state => {
const newState = {
...state,
isQuestMasterEnabled: settings.experimentalFeatures?.enableQuestMaster === true ? true : false,
isMementosEnabled: settings.experimentalFeatures?.enableMementos ?? false,
isArtifactsEnabled: settings.experimentalFeatures?.enableArtifacts ?? false,
};
return newState;
});
}, [settings.experimentalFeatures, setState]);

User Interface​

Users can toggle experimental features in their profile settings. The feature toggles are implemented in ExperimentalFeatureToggle.tsx:

// Helper function to check if a feature is enabled at the server level
const getServerSettingValue = (settingName: SettingKey): boolean => {
const setting = serverSettings?.find(s => s.settingName === settingName);
if (!setting) return false; // If setting doesn't exist, default to disabled
const value = setting.settingValue;
// Handle both string and number types
let interpreted: boolean;
if (typeof value === 'number') {
interpreted = value === 1;
} else {
interpreted = value === 'true' || value === '1' || value.toString() === 'true';
}
return interpreted;
};

The UI prevents users from enabling features that are not enabled at the server level.

Implementing a New Feature Flag​

To add a new experimental feature flag:

  1. Define the server-side flag:

    • Add the feature to settingsMap in settings.ts
    • Add it to the EXPERIMENTAL service group
    EnableNewFeature: makeBooleanSetting({
    key: 'EnableNewFeature',
    name: 'Enable New Feature',
    defaultValue: false,
    description: 'Description of the new feature.',
    category: 'Experimental',
    group: API_SERVICE_GROUPS.EXPERIMENTAL.id,
    order: 5, // Adjust order as needed
    }),
  2. Add the client-side flag:

    • Update the ExperimentalFeature type in UserSettingsContext.tsx
    • Add the feature to the default settings
    export type ExperimentalFeature = 
    'enableQuestMaster' |
    'enableMementos' |
    'enableArtifacts' |
    'enableOllama' |
    'enableNewFeature'; // Add new feature
  3. Add to the UI:

    • Update ExperimentalFeatureToggle.tsx to include the new feature
    • Add to allowedSettings in useExperimentalFeatureSettings hook
  4. Implement feature detection:

    • Add condition checks in relevant service code
    • Update API calls to pass the new feature flag
  5. Create the feature implementation:

    • Implement as a class that follows the ChatCompletionFeature interface pattern
    • Add to buildFeatures method in ChatCompletion.ts

Best Practices​

  • Default to Disabled: Always set defaultValue: false for new experimental features
  • Check Both Tiers: Always verify both server and user settings before enabling a feature
  • Clear UI Feedback: Provide clear descriptions and visual indicators for experimental features
  • Feature Documentation: Document the purpose and current limitations of each experimental feature
  • Error Handling: Include robust error handling in experimental feature code to prevent system-wide failures
  • Logging: Add detailed logging for experimental features to help diagnose issues

Conclusion​

The feature flag system provides a flexible way to roll out new functionality while minimizing risk. By utilizing both server-side and client-side flags, Bike4Mind ensures that experimental features can be rolled out gradually and safely.