feat(sdd): guard built-in SDD with experimental.sdd flag

This commit is contained in:
Jerop Kipruto
2026-03-17 14:14:35 -04:00
parent e1352ba8f2
commit b9c46d362b
5 changed files with 71 additions and 3 deletions

View File

@@ -36,6 +36,27 @@ SDD is designed to manage the entire lifecycle of your development tasks. It is
one of the [planning workflows](./plan-mode.md#planning-workflows) supported by
Gemini CLI.
### Enabling SDD
SDD is currently an experimental feature. To use it, you must enable the
`experimental.sdd` flag in your settings:
1. Open the settings dialog by running `/settings`.
2. Press `/` to enter search mode and type **SDD**.
3. Enable **Spec-Driven Development (SDD)**.
4. Restart the CLI for the changes to take effect.
Alternatively, you can navigate to the **Experimental** category to find the
setting, or enable it manually in your `~/.gemini/settings.json` file:
```json
{
"experimental": {
"sdd": true
}
}
```
**Note on Token Consumption:** SDD's context-driven approach involves reading
and analyzing your project's context, specifications, and plans. This can lead
to increased token consumption, especially in larger projects or during

View File

@@ -122,6 +122,11 @@
"slug": "docs/cli/notifications"
},
{ "label": "Plan mode", "slug": "docs/cli/plan-mode" },
{
"label": "Spec-driven development (SDD)",
"badge": "🔬",
"slug": "docs/cli/spec-driven-development"
},
{
"label": "Subagents",
"badge": "🔬",

View File

@@ -726,8 +726,10 @@ describe('ExtensionManager', () => {
const emitSpy = vi.spyOn(coreEvents, 'emitFeedback');
// Create a FRESH manager to ensure loadExtensions actually runs
const settings = createTestMergedSettings();
settings.experimental.sdd = true;
const manager = new ExtensionManager({
settings: createTestMergedSettings(),
settings,
workspaceDir: tempWorkspaceDir,
requestConsent: vi.fn().mockResolvedValue(true),
requestSetting: null,
@@ -765,8 +767,10 @@ describe('ExtensionManager', () => {
const emitSpy = vi.spyOn(coreEvents, 'emitFeedback');
// Create a FRESH manager
const settings = createTestMergedSettings();
settings.experimental.sdd = true;
const manager = new ExtensionManager({
settings: createTestMergedSettings(),
settings,
workspaceDir: tempWorkspaceDir,
requestConsent: vi.fn().mockResolvedValue(true),
requestSetting: null,
@@ -790,5 +794,29 @@ describe('ExtensionManager', () => {
expect.stringContaining('/spec setup'),
);
});
it('should NOT load sdd builtin when experimental.sdd is false', async () => {
// Create a builtin extension named 'sdd'
createExtension({
extensionsDir: builtinExtensionsDir,
name: 'sdd',
version: '1.0.0',
});
// Create a manager with default settings (experimental.sdd = false)
const settings = createTestMergedSettings();
settings.experimental.sdd = false;
const manager = new ExtensionManager({
settings,
workspaceDir: tempWorkspaceDir,
requestConsent: vi.fn().mockResolvedValue(true),
requestSetting: null,
});
const extensions = await manager.loadExtensions(builtinExtensionsDir);
// Verify builtin was NOT loaded
expect(extensions.find((e) => e.name === 'sdd')).toBeUndefined();
});
});
});

View File

@@ -671,6 +671,11 @@ Would you like to attempt to install via "git clone" instead?`,
for (const builtinExt of builtinResolved) {
if (builtinExt) {
const isSdd = builtinExt.name === 'sdd';
if (isSdd && !this.settings.experimental.sdd) {
continue;
}
const existingIdx = builtExtensions.findIndex(
(e) => e.name === builtinExt.name,
);
@@ -682,7 +687,7 @@ Would you like to attempt to install via "git clone" instead?`,
builtExtensions[existingIdx] = builtinExt;
} else {
// Check if this is the new 'sdd' extension and if 'conductor' is installed.
if (builtinExt.name === 'sdd') {
if (isSdd) {
const conductorIdx = builtExtensions.findIndex(
(e) => e.name === 'conductor',
);

View File

@@ -1955,6 +1955,15 @@ const SETTINGS_SCHEMA = {
description: 'Enable Plan Mode.',
showInDialog: true,
},
sdd: {
type: 'boolean',
label: 'Spec-Driven Development (SDD)',
category: 'Experimental',
requiresRestart: true,
default: false,
description: 'Enable built-in Spec-Driven Development (SDD) workflow.',
showInDialog: true,
},
taskTracker: {
type: 'boolean',
label: 'Task Tracker',