| name | VS Code Configuration Validation |
| description | Validate VS Code extension manifest against runtime code usage |
VS Code Extension Configuration Validation
Domain: VS Code extension development, configuration management, quality assurance
Complexity: Intermediate
Prerequisites: Understanding of VS Code extension manifest (package.json), TypeScript
Problem
VS Code extensions fail at runtime when:
- Configuration keys are updated without being registered in
package.json
- Commands are invoked but not declared in manifest
- Views/webviews reference unregistered IDs
- Context keys are set but not documented
These misconfigurations don't cause compile-time errors and only surface when users interact with specific features.
Solution
Systematic validation of VS Code extension manifest against runtime code usage.
1. Configuration Registration Validation
Check: All workspace.getConfiguration().update() calls reference registered properties.
await vscode.workspace.getConfiguration('alex.skillRecommendations')
.update('code-review.accepted', count + 1, ConfigurationTarget.Global);
try {
await vscode.workspace.getConfiguration('alex.skillRecommendations')
.update('code-review.accepted', count + 1, ConfigurationTarget.Global);
} catch (error) {
console.log(`Skip tracking: ${error}`);
}
Audit Pattern:
grep -r "getConfiguration.*\.update\(" src/
2. Command Registration Validation
Check: All commands.registerCommand() calls match declared commands in manifest.
vscode.commands.registerCommand('alex.validateHeir', async () => {...});
{
"contributes": {
"commands": [{
"command": "alex.validateHeir",
"title": "Validate as Heir Project"
}]
}
}
Audit Pattern:
grep -r "registerCommand\(['\"]alex\." src/
3. Configuration Read Validation
Check: All getConfiguration().get() calls match registered properties.
const enabled = vscode.workspace.getConfiguration('alex.voice').get('enabled', false);
Warning Pattern: Configuration reads with no defaults are risky:
const value = config.get('someKey');
const value = config.get('someKey', defaultValue);
4. Error Handling Patterns
For Dynamic Configuration Keys (skill recommendations, user preferences):
Option A: Register schema with dynamic pattern (complex)
Option B: Graceful try-catch (simple, recommended)
async function trackUserPreference(key: string, value: any) {
try {
await vscode.workspace.getConfiguration('alex.dynamic')
.update(key, value, ConfigurationTarget.Global);
} catch (error) {
console.log(`[Alex] Skipping preference tracking: ${error}`);
}
}
For Critical Configuration:
await vscode.workspace.getConfiguration('alex.globalKnowledge')
.update('remoteRepo', repo, ConfigurationTarget.Global);
Validation Checklist
Pre-Publish Review
Automated Audit Script
Create scripts/validate-manifest.ps1:
# Find all config updates
$updates = Select-String -Path "src/**/*.ts" -Pattern "getConfiguration\(['\"]([^'\"]+)['\"].*\.update\(['\"]([^'\"]+)"
# Load package.json properties
$manifest = Get-Content "package.json" | ConvertFrom-Json
$registered = $manifest.contributes.configuration.properties.PSObject.Properties.Name
# Check each update
$issues = @()
foreach ($match in $updates) {
$context = $match.Matches.Groups[1].Value
$key = $match.Matches.Groups[2].Value
$fullKey = "$context.$key"
if ($registered -notcontains $fullKey) {
# Check if wrapped in try-catch (manual review needed)
$issues += "⚠️ $fullKey - not registered (verify try-catch exists)"
}
}
if ($issues.Count -gt 0) {
Write-Host "Configuration validation issues:" -ForegroundColor Yellow
$issues | ForEach-Object { Write-Host $_ }
exit 1
}
Common Pitfalls
-
Dynamic Configuration Keys: User preferences, tracking counters
- Solution: Either register dynamic schema or use try-catch pattern
-
Namespaced Configuration: alex.skill.subkey.value
- Solution: Register full dotted path:
"alex.skill.subkey.value": {...}
-
Multi-Target Updates: Workspace vs Global vs WorkspaceFolder
- Solution: Test configuration across all scopes
-
Configuration Migration: Deprecated settings
- Solution: Use
deprecationMessage in property definition
Real-World Example: Skill Recommendations
Problem: Tracking skill usage without bloating package.json with hundreds of dynamic keys.
Solution: Graceful degradation pattern
async function trackRecommendation(skillId: string, accepted: boolean) {
try {
const context = 'alex.skillRecommendations';
const key = `${skillId}.${accepted ? 'accepted' : 'dismissed'}`;
const current = vscode.workspace.getConfiguration(context).get<number>(key, 0);
await vscode.workspace.getConfiguration(context).update(
key,
current + 1,
vscode.ConfigurationTarget.Global
);
} catch (error) {
console.log(`[Alex] Skipping recommendation tracking: ${error}`);
}
}
Why This Works:
- Feature works with or without tracking
- No user-facing error for unregistered config
- Logging helps debug if tracking is important
- Simple implementation vs complex dynamic schema
Integration with Existing QA
Add to .github/instructions/extension-audit-methodology.instructions.md:
### Configuration Validation
Before each release:
1. Run `scripts/validate-manifest.ps1`
2. Review any warnings for try-catch coverage
3. Test configuration updates in clean VS Code instance
4. Verify error messages are user-friendly
Resources
Sources of Truth:
- Incident: Skill recommendations broken due to unregistered config (2026-02-15)
- Root Cause:
alex.skillRecommendations.* keys not in package.json
- Fix: Try-catch wrapper in
src/chat/skillRecommendations.ts