From 34e0d669025eabdc684d96e4a4b23f24d851b75a Mon Sep 17 00:00:00 2001 From: Bryan Morgan Date: Sat, 31 Jan 2026 16:25:31 -0500 Subject: [PATCH] docs: restore experimentation framework proposal in new branch --- .../client-side-experimentation-framework.md | 1186 +++++++++++++++++ 1 file changed, 1186 insertions(+) create mode 100644 docs/proposals/client-side-experimentation-framework.md diff --git a/docs/proposals/client-side-experimentation-framework.md b/docs/proposals/client-side-experimentation-framework.md new file mode 100644 index 0000000000..8354f69719 --- /dev/null +++ b/docs/proposals/client-side-experimentation-framework.md @@ -0,0 +1,1186 @@ +# Client-Side Experimentation Framework Proposal for Gemini CLI + +> **Status:** Proposal **Author:** Generated Analysis **Date:** January 2026 + +--- + +## Executive Summary + +This document proposes a standardized framework for implementing client-side +experimental features in Gemini CLI. The goal is to enable developers to ship +features that users can opt into in a controlled, standardized way while +protecting users who don't opt-in. + +--- + +## Table of Contents + +1. [Current State Summary](#current-state-summary) +2. [Proposed Design](#proposed-design) +3. [Implementation Details](#implementation-details) +4. [Workflow Integration](#workflow-integration) +5. [User Experience](#user-experience) +6. [Graduation Process](#graduation-process) +7. [Industry Comparison](#industry-comparison) +8. [References](#references) + +--- + +## Current State Summary + +### What Gemini CLI Already Has + +| Capability | Location | Description | +| ------------------------- | ------------------- | --------------------------------------------------- | +| `experimental.*` settings | `settingsSchema.ts` | Boolean toggles for experimental features | +| `general.previewFeatures` | `settingsSchema.ts` | Preview model access control | +| Settings merge hierarchy | `settings.ts` | Schema defaults → System → User → Workspace → Admin | +| Agent experimental flags | `registry.ts` | `definition.experimental` on agent definitions | +| Remote admin controls | `settings.ts` | Server-side overrides for enterprise | + +### Current Experimental Features + +| Feature | Setting | Default | Purpose | +| ---------------------- | ----------------------------------------- | ------- | ------------------------------ | +| Agents | `experimental.enableAgents` | `false` | Enable subagent system | +| JIT Context | `experimental.jitContext` | `false` | Just-in-time context loading | +| Event-Driven Scheduler | `experimental.enableEventDrivenScheduler` | `true` | Event-based task orchestration | +| Plugin Hot-Reload | `experimental.extensionReloading` | `false` | Runtime plugin loading | +| Plugin Configuration | `experimental.extensionConfig` | `false` | Plugin settings management | +| Plugin Management | `experimental.extensionManagement` | `true` | Plugin lifecycle features | +| Plan Mode | `experimental.plan` | `false` | Read-only planning mode | +| OSC 52 Paste | `experimental.useOSC52Paste` | `false` | Remote session clipboard | +| Preview Models | `general.previewFeatures` | `false` | Access to preview models | + +### What's Missing + +- ❌ Standardized lifecycle for experimental features +- ❌ Clear graduation criteria (experimental → stable) +- ❌ Discoverability of experimental features +- ❌ Telemetry integration for experiment usage tracking +- ❌ Documentation automation for experimental features +- ❌ CLI-level opt-in flags (like Cargo's `-Z` flags) +- ❌ Feature dependency management +- ❌ Deprecation tracking and warnings + +--- + +## Proposed Design + +### Multi-Tier Feature Gate System + +#### Tier 1: Feature Lifecycle Stages + +Adopt a **Kubernetes-inspired maturity model** with clear stages: + +| Stage | Default | Stability | Can Remove? | Flag Required | +| -------------- | ------------ | ---------------------------------- | ------------------------ | --------------- | +| **Alpha** | `false` | May break, incomplete | Yes, any time | Explicit opt-in | +| **Beta** | `false` | Mostly stable, collecting feedback | Yes, with deprecation | Explicit opt-in | +| **GA** | `true` | Stable | No (breaking change) | None | +| **Deprecated** | `true→false` | Stable but discouraged | After deprecation period | None | + +#### Tier 2: Architecture Overview + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Feature Gate Registry │ +│ ┌──────────────────────────────────────────────────────────┐ │ +│ │ Feature Definition │ │ +│ │ - name: string │ │ +│ │ - stage: 'alpha' | 'beta' | 'ga' | 'deprecated' │ │ +│ │ - description: string │ │ +│ │ - owner: string (GitHub team/individual) │ │ +│ │ - trackingIssue: string (GitHub issue URL) │ │ +│ │ - addedIn: string (version) │ │ +│ │ - targetGAVersion?: string │ │ +│ │ - telemetryKey?: string │ │ +│ │ - requiresRestart: boolean │ │ +│ │ - dependencies?: string[] (other feature names) │ │ +│ └──────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Activation Methods │ +│ │ +│ 1. Settings File (persistent) │ +│ experimental.: true │ +│ │ +│ 2. CLI Flag (session-only, like Cargo's -Z) │ +│ gemini --feature= --feature= │ +│ gemini -X │ +│ │ +│ 3. Environment Variable (CI/testing) │ +│ GEMINI_FEATURES=, │ +│ │ +│ 4. Admin Override (enterprise) │ +│ Remote admin controls can force-enable/disable │ +└─────────────────────────────────────────────────────────────────┘ +``` + +#### Tier 3: Activation Priority (highest to lowest) + +1. **Admin Override** - Enterprise admins can force-enable or force-disable +2. **CLI Flags** - Session-specific activation via `--feature=X` +3. **Environment Variables** - `GEMINI_FEATURES=X,Y` for CI/testing +4. **Workspace Settings** - `.gemini/settings.json` (if workspace is trusted) +5. **User Settings** - `~/.gemini/settings.json` +6. **System Defaults** - Built-in defaults from feature definition + +--- + +## Implementation Details + +### 1. Feature Gate Registry + +**File:** `packages/core/src/features/featureGate.ts` + +```typescript +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +export enum FeatureStage { + /** Experimental, may break, can be removed any time */ + ALPHA = 'alpha', + /** Mostly stable, collecting feedback, requires deprecation to remove */ + BETA = 'beta', + /** Stable, always enabled, feature gate no longer needed */ + GA = 'ga', + /** Stable but discouraged, will be removed in future version */ + DEPRECATED = 'deprecated', +} + +export interface FeatureDefinition { + /** Unique identifier, kebab-case (e.g., "jit-context") */ + name: string; + + /** Current lifecycle stage */ + stage: FeatureStage; + + /** Human-readable description */ + description: string; + + /** GitHub team or individual responsible */ + owner: string; + + /** GitHub issue URL for tracking */ + trackingIssue?: string; + + /** Version when this feature was added */ + addedInVersion: string; + + /** Target version for GA (if alpha/beta) */ + targetGAVersion?: string; + + /** Version when deprecated (if deprecated) */ + deprecatedInVersion?: string; + + /** Version when feature will be removed (if deprecated) */ + removalVersion?: string; + + /** Whether enabling/disabling requires CLI restart */ + requiresRestart: boolean; + + /** Other features this depends on */ + dependencies?: string[]; + + /** Key for telemetry tracking */ + telemetryKey?: string; + + /** Warning message shown when feature is enabled */ + warningMessage?: string; + + /** Features that are mutually exclusive with this one */ + conflictsWith?: string[]; +} + +/** + * Central registry of all feature gates. + * + * To add a new feature: + * 1. Create a tracking issue + * 2. Add entry here with stage: ALPHA + * 3. Implement feature gated by FeatureGateService.isEnabled() + * 4. Graduate through stages based on feedback + */ +export const FEATURE_GATES: Record = { + 'jit-context': { + name: 'jit-context', + stage: FeatureStage.ALPHA, + description: 'Just-in-time context loading for improved memory usage', + owner: '@anthropics/gemini-cli', + trackingIssue: 'https://github.com/google-gemini/gemini-cli/issues/XXX', + addedInVersion: '0.25.0', + targetGAVersion: '1.0.0', + requiresRestart: true, + telemetryKey: 'feature_jit_context', + warningMessage: + 'JIT context is experimental and may affect response quality.', + }, + + agents: { + name: 'agents', + stage: FeatureStage.ALPHA, + description: 'Enable subagent system for complex multi-step tasks', + owner: '@anthropics/gemini-cli', + trackingIssue: 'https://github.com/google-gemini/gemini-cli/issues/XXX', + addedInVersion: '0.20.0', + requiresRestart: false, + telemetryKey: 'feature_agents', + warningMessage: 'Agents run in YOLO mode and will auto-approve tool calls.', + }, + + 'plan-mode': { + name: 'plan-mode', + stage: FeatureStage.BETA, + description: + 'Read-only planning mode for reviewing changes before execution', + owner: '@anthropics/gemini-cli', + trackingIssue: 'https://github.com/google-gemini/gemini-cli/issues/XXX', + addedInVersion: '0.22.0', + targetGAVersion: '0.30.0', + requiresRestart: false, + telemetryKey: 'feature_plan_mode', + }, + + 'event-driven-scheduler': { + name: 'event-driven-scheduler', + stage: FeatureStage.BETA, + description: 'Event-based task orchestration system', + owner: '@anthropics/gemini-cli', + addedInVersion: '0.18.0', + requiresRestart: true, + telemetryKey: 'feature_event_scheduler', + }, + + // Example of a deprecated feature + 'legacy-context-loading': { + name: 'legacy-context-loading', + stage: FeatureStage.DEPRECATED, + description: 'Legacy context loading (use jit-context instead)', + owner: '@anthropics/gemini-cli', + addedInVersion: '0.10.0', + deprecatedInVersion: '0.25.0', + removalVersion: '1.0.0', + requiresRestart: true, + warningMessage: + 'This feature is deprecated and will be removed in v1.0.0. Migrate to jit-context.', + }, +}; + +/** + * Get all features at a specific stage + */ +export function getFeaturesByStage(stage: FeatureStage): FeatureDefinition[] { + return Object.values(FEATURE_GATES).filter((f) => f.stage === stage); +} + +/** + * Get a feature definition by name + */ +export function getFeature(name: string): FeatureDefinition | undefined { + return FEATURE_GATES[name]; +} + +/** + * Check if a feature name is valid + */ +export function isValidFeature(name: string): boolean { + return name in FEATURE_GATES; +} +``` + +### 2. Feature Gate Service + +**File:** `packages/core/src/features/featureGateService.ts` + +```typescript +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + FEATURE_GATES, + FeatureStage, + getFeature, + isValidFeature, + type FeatureDefinition, +} from './featureGate.js'; +import { debugLogger } from '../utils/debugLogger.js'; + +export interface FeatureGateServiceConfig { + /** Features enabled via settings file */ + settingsFeatures: Record; + + /** Features enabled via CLI flags */ + cliFeatures: string[]; + + /** Features enabled via environment variable */ + envFeatures: string[]; + + /** Admin overrides (highest priority) */ + adminOverrides: Record; +} + +export class FeatureGateService { + private readonly enabledFeatures: Set = new Set(); + private readonly config: FeatureGateServiceConfig; + + constructor(config: FeatureGateServiceConfig) { + this.config = config; + this.computeEnabledFeatures(); + } + + /** + * Check if a feature is enabled + */ + isEnabled(featureName: string): boolean { + const definition = getFeature(featureName); + + if (!definition) { + debugLogger.warn(`Unknown feature gate: ${featureName}`); + return false; + } + + // GA features are always enabled + if (definition.stage === FeatureStage.GA) { + return true; + } + + // Admin override takes highest priority + if (this.config.adminOverrides[featureName] !== undefined) { + return this.config.adminOverrides[featureName]; + } + + return this.enabledFeatures.has(featureName); + } + + /** + * Get all currently enabled features + */ + getEnabledFeatures(): FeatureDefinition[] { + return [...this.enabledFeatures] + .map((name) => getFeature(name)) + .filter((f): f is FeatureDefinition => f !== undefined); + } + + /** + * Get enabled features at a specific stage + */ + getEnabledFeaturesAtStage(stage: FeatureStage): FeatureDefinition[] { + return this.getEnabledFeatures().filter((f) => f.stage === stage); + } + + /** + * Get warnings for enabled experimental features + */ + getStartupWarnings(): string[] { + const warnings: string[] = []; + + for (const feature of this.getEnabledFeatures()) { + if (feature.stage === FeatureStage.ALPHA && feature.warningMessage) { + warnings.push(`⚠️ [ALPHA] ${feature.name}: ${feature.warningMessage}`); + } else if ( + feature.stage === FeatureStage.DEPRECATED && + feature.warningMessage + ) { + warnings.push( + `⚠️ [DEPRECATED] ${feature.name}: ${feature.warningMessage}`, + ); + } + } + + return warnings; + } + + /** + * Validate feature dependencies + */ + validateDependencies(): string[] { + const errors: string[] = []; + + for (const featureName of this.enabledFeatures) { + const feature = getFeature(featureName); + if (!feature?.dependencies) continue; + + for (const dep of feature.dependencies) { + if (!this.isEnabled(dep)) { + errors.push( + `Feature "${featureName}" requires "${dep}" to be enabled`, + ); + } + } + + // Check for conflicts + if (feature.conflictsWith) { + for (const conflict of feature.conflictsWith) { + if (this.isEnabled(conflict)) { + errors.push( + `Feature "${featureName}" conflicts with "${conflict}"`, + ); + } + } + } + } + + return errors; + } + + private computeEnabledFeatures(): void { + this.enabledFeatures.clear(); + + // Process in order of priority (lowest to highest) + // 1. Settings file + for (const [name, enabled] of Object.entries( + this.config.settingsFeatures, + )) { + if (enabled && isValidFeature(name)) { + this.enabledFeatures.add(name); + } + } + + // 2. Environment variables + for (const name of this.config.envFeatures) { + if (isValidFeature(name)) { + this.enabledFeatures.add(name); + } else { + debugLogger.warn(`Unknown feature in GEMINI_FEATURES: ${name}`); + } + } + + // 3. CLI flags (can also disable with --no-feature=X) + for (const name of this.config.cliFeatures) { + if (name.startsWith('no-')) { + const featureName = name.slice(3); + this.enabledFeatures.delete(featureName); + } else if (isValidFeature(name)) { + this.enabledFeatures.add(name); + } else { + debugLogger.warn(`Unknown feature flag: ${name}`); + } + } + + // Note: Admin overrides are checked at runtime in isEnabled() + } +} +``` + +### 3. CLI Flag Support + +**File:** `packages/cli/src/config/config.ts` (additions) + +```typescript +// Add to yargs options +.option('feature', { + alias: 'X', + type: 'array', + string: true, + description: 'Enable experimental feature(s) for this session. Use --feature= or -X ', + coerce: (features: string[]) => + features.flatMap(f => f.split(',').map(x => x.trim())), +}) +.option('no-feature', { + type: 'array', + string: true, + description: 'Disable a feature for this session', + coerce: (features: string[]) => + features.flatMap(f => f.split(',').map(x => x.trim())), +}) +.option('list-features', { + type: 'boolean', + description: 'List all available feature gates and exit', +}) +``` + +### 4. Environment Variable Support + +```typescript +// In loadCliConfig or similar +function parseEnvFeatures(): string[] { + const envValue = process.env['GEMINI_FEATURES']; + if (!envValue) return []; + + return envValue + .split(',') + .map((f) => f.trim()) + .filter((f) => f.length > 0); +} +``` + +### 5. `/features` Slash Command + +**File:** `packages/cli/src/commands/features.ts` + +```typescript +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + FEATURE_GATES, + FeatureStage, + getFeaturesByStage, +} from '@google/gemini-cli-core'; +import type { Config } from '@google/gemini-cli-core'; + +export async function featuresCommand(config: Config): Promise { + const featureService = config.getFeatureGateService(); + + console.log(' +📋 Gemini CLI Feature Gates +'); + console.log( + 'Feature gates allow you to opt-in to experimental functionality. +', + ); + + // Alpha features + const alphaFeatures = getFeaturesByStage(FeatureStage.ALPHA); + if (alphaFeatures.length > 0) { + console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); + console.log('ALPHA Features (experimental, may change without notice)'); + console.log( + '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +', + ); + + for (const feature of alphaFeatures) { + const enabled = featureService.isEnabled(feature.name); + const status = enabled ? '✓ ENABLED' : '○ disabled'; + + console.log(` ${feature.name}`); + console.log(` Status: ${status}`); + console.log(` ${feature.description}`); + if (feature.trackingIssue) { + console.log(` Tracking: ${feature.trackingIssue}`); + } + if (feature.targetGAVersion) { + console.log(` Target GA: v${feature.targetGAVersion}`); + } + console.log(); + } + } + + // Beta features + const betaFeatures = getFeaturesByStage(FeatureStage.BETA); + if (betaFeatures.length > 0) { + console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); + console.log('BETA Features (mostly stable, feedback welcome)'); + console.log( + '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +', + ); + + for (const feature of betaFeatures) { + const enabled = featureService.isEnabled(feature.name); + const status = enabled ? '✓ ENABLED' : '○ disabled'; + + console.log(` ${feature.name}`); + console.log(` Status: ${status}`); + console.log(` ${feature.description}`); + if (feature.trackingIssue) { + console.log(` Tracking: ${feature.trackingIssue}`); + } + console.log(); + } + } + + // Deprecated features + const deprecatedFeatures = getFeaturesByStage(FeatureStage.DEPRECATED); + if (deprecatedFeatures.length > 0) { + console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); + console.log('DEPRECATED Features (will be removed)'); + console.log( + '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +', + ); + + for (const feature of deprecatedFeatures) { + const enabled = featureService.isEnabled(feature.name); + const status = enabled ? '✓ ENABLED' : '○ disabled'; + + console.log(` ${feature.name}`); + console.log(` Status: ${status}`); + console.log(` ${feature.description}`); + if (feature.removalVersion) { + console.log(` ⚠️ Will be removed in: v${feature.removalVersion}`); + } + console.log(); + } + } + + // Usage instructions + console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); + console.log('How to Enable Features'); + console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +'); + console.log(' CLI flag (session only):'); + console.log(' gemini --feature='); + console.log(' gemini -X '); + console.log(); + console.log(' Environment variable (CI/testing):'); + console.log(' GEMINI_FEATURES=, gemini'); + console.log(); + console.log(' Settings file (persistent):'); + console.log(' Add to ~/.gemini/settings.json:'); + console.log(' { "experimental": { "": true } }'); + console.log(); +} +``` + +### 6. Settings Schema Auto-Generation + +**File:** `packages/cli/src/config/settingsSchema.ts` (additions) + +```typescript +import { FEATURE_GATES, FeatureStage } from '@google/gemini-cli-core'; + +/** + * Auto-generate experimental settings schema from feature definitions. + * This ensures the settings schema stays in sync with feature gates. + */ +function generateExperimentalSchema(): Record { + const schema: Record = {}; + + for (const [name, def] of Object.entries(FEATURE_GATES)) { + // GA features don't need settings (always enabled) + if (def.stage === FeatureStage.GA) continue; + + // Convert kebab-case to camelCase for settings + const settingName = name.replace(/-([a-z])/g, (_, c) => c.toUpperCase()); + + schema[settingName] = { + type: 'boolean', + default: false, + label: `[${def.stage.toUpperCase()}] ${def.name}`, + description: + def.description + + (def.warningMessage ? ` ⚠️ ${def.warningMessage}` : ''), + showInDialog: def.stage === FeatureStage.BETA, // Only show beta in settings UI + requiresRestart: def.requiresRestart, + ignoreInDocs: def.stage === FeatureStage.ALPHA, // Don't document alpha features + }; + } + + return schema; +} + +// Use in schema definition +export const settingsSchema = { + // ... other settings ... + + experimental: { + type: 'object', + label: 'Experimental Features', + description: + 'Enable experimental features. Use /features to see all available.', + properties: generateExperimentalSchema(), + }, +}; +``` + +### 7. Telemetry Integration + +**File:** `packages/core/src/telemetry/featureTelemetry.ts` + +```typescript +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { getFeature } from '../features/featureGate.js'; +import type { Config } from '../config/config.js'; + +export interface FeatureUsageEvent { + featureName: string; + stage: string; + action: 'enabled' | 'used' | 'error'; + clientVersion: string; + sessionId: string; + timestamp: string; +} + +/** + * Log when a feature is enabled at startup + */ +export function logFeatureEnabled(config: Config, featureName: string): void { + const definition = getFeature(featureName); + if (!definition?.telemetryKey) return; + + // Use existing telemetry infrastructure + config.getTelemetryService()?.recordEvent({ + name: 'feature_enabled', + attributes: { + feature: featureName, + stage: definition.stage, + version: config.getClientVersion(), + }, + }); +} + +/** + * Log when a feature is actively used + */ +export function logFeatureUsed(config: Config, featureName: string): void { + const definition = getFeature(featureName); + if (!definition?.telemetryKey) return; + + config.getTelemetryService()?.recordEvent({ + name: 'feature_used', + attributes: { + feature: featureName, + stage: definition.stage, + version: config.getClientVersion(), + }, + }); +} +``` + +--- + +## Workflow Integration + +### 1. Feature Tracking Issue Template + +**File:** `.github/ISSUE_TEMPLATE/feature-gate.yml` + +```yaml +name: Feature Gate Proposal +description: Propose a new experimental feature gate +title: '[Feature Gate] ' +labels: ['type/feature-gate', 'stage/alpha'] +body: + - type: markdown + attributes: + value: | + ## Feature Gate Proposal + + Use this template to propose a new experimental feature for Gemini CLI. + All new features should start as Alpha and graduate through stages. + + - type: input + id: feature-name + attributes: + label: Feature Name + description: Lowercase, kebab-case identifier (e.g., "jit-context") + placeholder: my-feature-name + validations: + required: true + + - type: dropdown + id: initial-stage + attributes: + label: Initial Stage + description: Most features should start as Alpha + options: + - alpha + - beta + default: 0 + validations: + required: true + + - type: textarea + id: description + attributes: + label: Description + description: What does this feature do? (This will be shown to users) + placeholder: A brief description of the feature's functionality + validations: + required: true + + - type: textarea + id: motivation + attributes: + label: Motivation + description: Why is this feature needed? What problem does it solve? + validations: + required: true + + - type: input + id: target-ga + attributes: + label: Target GA Version + description: When do you expect this to be stable? (e.g., "1.0.0") + placeholder: '1.0.0' + + - type: textarea + id: graduation-criteria + attributes: + label: Graduation Criteria + description: What needs to happen for this to move from Alpha → Beta → GA? + value: | + ### Alpha → Beta + - [ ] Feature is functionally complete + - [ ] No critical bugs reported for 2 weeks + - [ ] Basic documentation exists + - [ ] Telemetry shows stable usage patterns + + ### Beta → GA + - [ ] Feature has been in Beta for 4+ weeks + - [ ] Documentation is complete + - [ ] No breaking changes planned + - [ ] Team consensus achieved + validations: + required: true + + - type: textarea + id: warning-message + attributes: + label: Warning Message + description: Optional warning shown when users enable this feature + placeholder: 'This feature may affect performance in large codebases.' + + - type: checkboxes + id: requirements + attributes: + label: Requirements + options: + - label: Requires CLI restart when toggled + - label: Has dependencies on other features + - label: Conflicts with other features +``` + +### 2. Automated Documentation Workflow + +**File:** `.github/workflows/docs-features.yml` + +```yaml +name: Update Feature Documentation + +on: + push: + branches: [main] + paths: + - 'packages/core/src/features/featureGate.ts' + workflow_dispatch: + +jobs: + update-docs: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Generate feature documentation + run: npm run docs:generate-features + + - name: Check for changes + id: changes + run: | + if [[ -n $(git status --porcelain docs/experimental-features.md) ]]; then + echo "changed=true" >> $GITHUB_OUTPUT + fi + + - name: Create Pull Request + if: steps.changes.outputs.changed == 'true' + uses: peter-evans/create-pull-request@v5 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: 'docs: Update experimental features documentation' + title: 'docs: Update experimental features documentation' + body: | + This PR was automatically generated to update the experimental features documentation. + + The feature gate definitions in `packages/core/src/features/featureGate.ts` have changed. + branch: docs/update-features + labels: documentation,automated +``` + +### 3. Feature Gate Validation in CI + +**File:** `.github/workflows/ci.yml` (additions) + +```yaml +validate-features: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Validate feature gates + run: npm run validate:features + # This script should: + # - Check all features have tracking issues + # - Check deprecated features have removal versions + # - Check feature names follow conventions + # - Check for orphaned feature flags in code +``` + +--- + +## User Experience + +### Enabling via CLI Flag + +```bash +# Single feature +gemini --feature=jit-context "Analyze this codebase" + +# Short form +gemini -X jit-context "Analyze this codebase" + +# Multiple features +gemini --feature=jit-context --feature=agents "Help me refactor" + +# Comma-separated +gemini -X jit-context,agents + +# Disable a feature for this session +gemini --no-feature=event-driven-scheduler +``` + +### Enabling via Environment Variable + +```bash +# For CI/CD or testing +GEMINI_FEATURES=jit-context,agents gemini -p "Run tests" + +# In a shell profile for persistent enablement +export GEMINI_FEATURES=jit-context +``` + +### Enabling via Settings File + +```json +// ~/.gemini/settings.json +{ + "experimental": { + "jitContext": true, + "agents": true, + "planMode": true + } +} +``` + +### Listing Features + +``` +$ gemini --list-features + +📋 Gemini CLI Feature Gates + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +ALPHA Features (experimental, may change without notice) +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + jit-context + Status: ○ disabled + Just-in-time context loading for improved memory usage + Tracking: https://github.com/google-gemini/gemini-cli/issues/XXX + Target GA: v1.0.0 + + agents + Status: ○ disabled + Enable subagent system for complex multi-step tasks + Tracking: https://github.com/google-gemini/gemini-cli/issues/XXX + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +BETA Features (mostly stable, feedback welcome) +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + plan-mode + Status: ○ disabled + Read-only planning mode for reviewing changes before execution + Tracking: https://github.com/google-gemini/gemini-cli/issues/XXX + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +How to Enable Features +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + CLI flag (session only): + gemini --feature= + gemini -X + + Environment variable (CI/testing): + GEMINI_FEATURES=, gemini + + Settings file (persistent): + Add to ~/.gemini/settings.json: + { "experimental": { "": true } } +``` + +### Startup Warnings + +``` +$ gemini --feature=agents + +⚠️ Experimental features enabled: + • [ALPHA] agents: Agents run in YOLO mode and will auto-approve tool calls. + +Type /features to learn more about experimental features. + +> +``` + +--- + +## Graduation Process + +### Stage Transitions + +``` + ┌─────────────┐ + │ ALPHA │ + │ (2+ weeks) │ + └──────┬──────┘ + │ + ┌──────────────┼──────────────┐ + │ │ │ + ▼ │ ▼ + ┌─────────────┐ │ ┌─────────────┐ + │ BETA │ │ │ REMOVED │ + │ (4+ weeks) │ │ │ (failed) │ + └──────┬──────┘ │ └─────────────┘ + │ │ + │ │ + ▼ │ + ┌─────────────┐ │ + │ GA │◄──────┘ + │ (stable) │ + └──────┬──────┘ + │ + ▼ + ┌─────────────┐ + │ DEPRECATED │ + │ (optional) │ + └──────┬──────┘ + │ + ▼ + ┌─────────────┐ + │ REMOVED │ + └─────────────┘ +``` + +### Alpha → Beta Criteria + +- [ ] Feature is functionally complete +- [ ] At least 2 weeks since Alpha release +- [ ] No critical bugs reported +- [ ] Basic documentation exists +- [ ] Telemetry shows no major issues +- [ ] Tracking issue updated with feedback summary + +### Beta → GA Criteria + +- [ ] At least 4 weeks in Beta +- [ ] Telemetry shows stable usage patterns +- [ ] Documentation is complete +- [ ] No breaking changes planned +- [ ] Team consensus in tracking issue +- [ ] Feature gate can be removed (always enabled) + +### GA → Deprecated Criteria + +- [ ] Replacement feature available (if applicable) +- [ ] Deprecation warning added to feature definition +- [ ] Migration guide published +- [ ] Removal version announced (typically N+2 major versions) + +### Deprecation Timeline + +| Action | Timeline | +| ------------------------ | ----------- | +| Mark as deprecated | Version N | +| Log deprecation warnings | Version N | +| Disable by default | Version N+1 | +| Remove feature | Version N+2 | + +--- + +## Industry Comparison + +| Aspect | Gemini CLI (Proposed) | [Cargo (Rust)](https://doc.rust-lang.org/cargo/reference/unstable.html) | [Kubernetes](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/) | +| ------------------ | ------------------------ | ----------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | +| **Stages** | Alpha/Beta/GA/Deprecated | Unstable/Stable | Alpha/Beta/GA | +| **CLI Flag** | `--feature=X` / `-X` | `-Z flag` | `--feature-gates=X=true` | +| **Config File** | `experimental.X: true` | `[unstable] X = true` | Component flags | +| **Default Off** | Alpha, Beta | All unstable | Alpha only | +| **Nightly Only** | No (available in all) | Yes | No | +| **Tracking** | GitHub Issues | Tracking Issues | KEPs | +| **Telemetry** | Optional | None | Metrics endpoint | +| **Admin Override** | Yes | No | No | + +--- + +## References + +### Open Source Feature Flag Tools + +- [OpenFeature](https://openfeature.dev/) - Vendor-agnostic feature flagging + specification (CNCF) +- [GrowthBook](https://www.growthbook.io/) - Open source feature flags and A/B + testing +- [Flagsmith](https://www.flagsmith.com/) - Open source feature flag service +- [Unleash](https://www.getunleash.io/) - Open source feature management + +### CLI Tool Implementations + +- [Cargo Unstable Features](https://doc.rust-lang.org/cargo/reference/unstable.html) - + Rust's package manager experimental features +- [Kubernetes Feature Gates](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/) - + K8s feature gate system +- [Feature Flags Best Practices - LaunchDarkly](https://launchdarkly.com/blog/what-are-feature-flags/) + +### Internal References + +- Current experimental settings: `packages/cli/src/config/settingsSchema.ts` +- Settings merge logic: `packages/cli/src/config/settings.ts` +- Agent experimental flags: `packages/core/src/agents/registry.ts` +- Release workflows: `.github/workflows/release-*.yml` + +--- + +## Appendix: Migration Path + +### Migrating Existing Experimental Features + +The following existing experimental settings should be migrated to the new +feature gate system: + +| Current Setting | New Feature Gate | Stage | +| ----------------------------------------- | ------------------------ | ----- | +| `experimental.enableAgents` | `agents` | Alpha | +| `experimental.jitContext` | `jit-context` | Alpha | +| `experimental.plan` | `plan-mode` | Beta | +| `experimental.enableEventDrivenScheduler` | `event-driven-scheduler` | Beta | +| `experimental.extensionReloading` | `extension-reloading` | Alpha | +| `experimental.extensionConfig` | `extension-config` | Alpha | +| `experimental.useOSC52Paste` | `osc52-paste` | Alpha | +| `general.previewFeatures` | `preview-models` | Beta | + +A migration script should: + +1. Read existing settings +2. Map to new feature gate names +3. Preserve user preferences +4. Log migration actions