feat: increase command limit to 100 and add optimization guide

Changes:
- Increase command limit from 50 to 100 per project
- Add examples/OPTIMIZE_CONFIG.md with optimization strategies
- Update all documentation references (50 → 100)
- Update tests for new limit

Rationale:
- 50 was too restrictive for projects with many tools (Flutter, etc.)
- Users were unknowingly exceeding limit by listing subcommands
- 100 provides headroom while maintaining security
- New guide teaches wildcard optimization (flutter* vs listing each subcommand)

UI feedback idea: Show command count and optimization suggestions
(tracked for Phase 3 or future enhancement)
This commit is contained in:
Marian Paul
2026-01-22 13:29:33 +01:00
parent d1dac1383d
commit f1b48be10e
7 changed files with 249 additions and 19 deletions

View File

@@ -233,7 +233,7 @@ blocked_commands:
- Scripts: `./scripts/build.sh` matches the script by name from any directory
**Limits:**
- Maximum 50 commands per project config
- Maximum 100 commands per project config
- Blocklisted commands (sudo, dd, shutdown, etc.) can NEVER be allowed
- Org-level blocked commands cannot be overridden by project configs

230
examples/OPTIMIZE_CONFIG.md Normal file
View File

@@ -0,0 +1,230 @@
# How to Optimize Your allowed_commands.yaml
## The Problem
Your config might have redundant commands like this:
```yaml
commands:
- name: flutter
- name: flutter* # ← This already covers EVERYTHING below!
- name: flutter test # ← Redundant
- name: flutter test --coverage # ← Redundant
- name: flutter build apk # ← Redundant
- name: flutter build ios # ← Redundant
# ... 20+ more flutter commands
```
**Result:** 65 commands when you only need ~10-15
## How Wildcards Work
When you have `flutter*`, it matches:
-`flutter` (the base command)
-`flutter test`
-`flutter test --coverage`
-`flutter build apk`
-`flutter build ios`
-`flutter run`
-**ANY command starting with "flutter"**
**You don't need to list every subcommand separately!**
## Example: GOD-APP Optimization
### Before (65 commands)
```yaml
commands:
# Flutter
- name: flutter
- name: flutter*
- name: flutter test
- name: flutter test --coverage
- name: flutter test --exclude-tags=golden,integration
- name: flutter test --tags=golden
- name: flutter test --tags=golden --update-goldens
- name: flutter test --verbose
- name: flutter drive
- name: flutter test integration_test/
- name: flutter build apk
- name: flutter build apk --debug
- name: flutter build apk --release
- name: flutter build appbundle
- name: flutter build ios
- name: flutter build ios --debug
- name: flutter build ipa
- name: flutter build web
- name: flutter pub get
- name: flutter pub upgrade
- name: flutter doctor
- name: flutter clean
# ... and more
# Dart
- name: dart
- name: dartfmt
- name: dartanalyzer
- name: dart format
- name: dart analyze
- name: dart fix
- name: dart pub
```
### After (15 commands) ✨
```yaml
commands:
# Flutter & Dart (wildcards cover all subcommands)
- name: flutter*
description: All Flutter SDK commands
- name: dart*
description: All Dart language tools
# Testing tools
- name: patrol
description: Patrol integration testing (if needed separately)
# Coverage tools
- name: lcov
description: Code coverage tool
- name: genhtml
description: Generate HTML coverage reports
# Android tools
- name: adb*
description: Android Debug Bridge commands
- name: gradle*
description: Gradle build system
# iOS tools (macOS only)
- name: xcrun*
description: Xcode developer tools
- name: xcodebuild
description: Xcode build system
- name: simctl
description: iOS Simulator control
- name: ios-deploy
description: Deploy to iOS devices
# Project scripts
- name: ./scripts/*.sh
description: All project build/test scripts
```
**Reduced from 65 → 15 commands (77% reduction!)**
## Optimization Checklist
For each group of commands, ask:
### ❓ "Do I have the base command AND a wildcard?"
```yaml
# Bad (redundant)
- name: flutter
- name: flutter*
# Good (just the wildcard)
- name: flutter*
```
The wildcard already matches the base command!
### ❓ "Am I listing subcommands individually?"
```yaml
# Bad (verbose)
- name: flutter test
- name: flutter test --coverage
- name: flutter build apk
- name: flutter run
# Good (one wildcard)
- name: flutter*
```
### ❓ "Can I group multiple scripts?"
```yaml
# If you can't use wildcards for scripts, at least group them logically
- name: ./scripts/test.sh
- name: ./scripts/build.sh
- name: ./scripts/integration_test.sh
```
These are fine - scripts need explicit paths. But if you have 20+ scripts, consider if they're all necessary.
## Common Wildcards
| Instead of... | Use... | Covers |
|---------------|--------|--------|
| flutter, flutter test, flutter build, flutter run | `flutter*` | All flutter commands |
| dart, dart format, dart analyze, dart pub | `dart*` | All dart commands |
| npm, npm install, npm run, npm test | `npm*` | All npm commands |
| cargo, cargo build, cargo test, cargo run | `cargo*` | All cargo commands |
| git, git status, git commit, git push | Just `git` | Git is in global defaults |
## When NOT to Optimize
Keep separate entries when:
1. **Different base commands:** `swift` and `swiftc` are different (though `swift*` covers both)
2. **Documentation clarity:** Sometimes listing helps future developers understand what's needed
3. **Argument restrictions (Phase 3):** If you'll add argument validation later
## Quick Optimization Script
To see what you can reduce:
```bash
# Count commands by prefix
grep "^ - name:" .autocoder/allowed_commands.yaml | \
sed 's/^ - name: //' | \
cut -d' ' -f1 | \
sort | uniq -c | sort -rn
```
If you see multiple commands with the same prefix, use a wildcard!
## UI Feedback (Future Enhancement)
Great suggestion! Here's what a UI could show:
```
⚠️ Config Optimization Available
Your config has 65 commands. We detected opportunities to reduce it:
• 25 flutter commands → Use flutter* (saves 24 entries)
• 8 dart commands → Use dart* (saves 7 entries)
• 12 adb commands → Use adb* (saves 11 entries)
[Optimize Automatically] [Keep As-Is]
Potential reduction: 65 → 23 commands
```
Or during config editing:
```
📊 Command Usage Stats
flutter* : 25 subcommands detected
dart* : 8 subcommands detected
./scripts/*.sh : 7 scripts detected
💡 Tip: Using wildcards covers all subcommands automatically
```
**This would be a great addition to Phase 3 or beyond!**
## Your GOD-APP Optimization
Here's what you could do:
**Current:** 65 commands (exceeds 50 limit, config rejected!)
**Optimized:** ~15 commands using wildcards
Would you like me to create an optimized version of your GOD-APP config?

View File

@@ -72,7 +72,7 @@ commands:
- ✅ Temporary tools needed during development
**Limits:**
- Maximum 50 commands per project
- Maximum 100 commands per project
- Cannot override org-level blocked commands
- Cannot allow hardcoded blocklist commands (sudo, dd, etc.)
@@ -321,13 +321,13 @@ blocked_commands: [] # Rely on hardcoded blocklist only
- Bad: Adding `xcodebuild` to org config when only one project uses it
- Good: Add `xcodebuild` to that project's config
4. **Don't exceed the 50 command limit per project**
- If you need more, you're probably being too specific
- Use wildcards instead: `npm-*` covers many npm tools
4. **Don't exceed the 100 command limit per project**
- If you need more, you're probably listing subcommands unnecessarily
- Use wildcards instead: `flutter*` covers all flutter commands, not just the base
5. **Don't ignore validation errors**
- If your YAML is rejected, fix the structure
- Common issues: missing `version`, malformed lists, over 50 commands
- Common issues: missing `version`, malformed lists, over 100 commands
---

View File

@@ -113,7 +113,7 @@ commands: []
# - Scripts: "./scripts/build.sh" matches the script by name
#
# Limits:
# - Maximum 50 commands per project
# - Maximum 100 commands per project
# - Commands in the blocklist (sudo, dd, shutdown, etc.) can NEVER be allowed
# - Org-level blocked commands (see ~/.autocoder/config.yaml) cannot be overridden
#

View File

@@ -491,8 +491,8 @@ def load_project_commands(project_dir: Path) -> Optional[dict]:
if not isinstance(commands, list):
return None
# Enforce 50 command limit
if len(commands) > 50:
# Enforce 100 command limit
if len(commands) > 100:
return None
# Validate each command entry

View File

@@ -263,8 +263,8 @@ commands:
print(f" Got: {config}")
failed += 1
# Test 4: Over limit (50 commands)
commands = [f" - name: cmd{i}\n description: Command {i}" for i in range(51)]
# Test 4: Over limit (100 commands)
commands = [f" - name: cmd{i}\n description: Command {i}" for i in range(101)]
config_path.write_text("version: 1\ncommands:\n" + "\n".join(commands))
config = load_project_commands(project_dir)
if config is None:

View File

@@ -326,21 +326,21 @@ def test_invalid_yaml_ignored():
return False
def test_50_command_limit():
"""Test that configs with >50 commands are rejected."""
def test_100_command_limit():
"""Test that configs with >100 commands are rejected."""
print("\n" + "=" * 70)
print("TEST 9: 50 command limit enforced")
print("TEST 9: 100 command limit enforced")
print("=" * 70)
with tempfile.TemporaryDirectory() as tmpdir:
project_dir = Path(tmpdir)
# Create config with 51 commands
# Create config with 101 commands
autocoder_dir = project_dir / ".autocoder"
autocoder_dir.mkdir()
commands = [
f" - name: cmd{i}\n description: Command {i}" for i in range(51)
f" - name: cmd{i}\n description: Command {i}" for i in range(101)
]
(autocoder_dir / "allowed_commands.yaml").write_text(
"version: 1\ncommands:\n" + "\n".join(commands)
@@ -353,10 +353,10 @@ def test_50_command_limit():
result = asyncio.run(bash_security_hook(input_data, context=context))
if result.get("decision") == "block":
print("✅ PASS: Config with >50 commands rejected")
print("✅ PASS: Config with >100 commands rejected")
return True
else:
print("❌ FAIL: Config with >50 commands should be rejected")
print("❌ FAIL: Config with >100 commands should be rejected")
return False
@@ -376,7 +376,7 @@ def main():
test_org_blocklist_enforcement,
test_org_allowlist_inheritance,
test_invalid_yaml_ignored,
test_50_command_limit,
test_100_command_limit,
]
passed = 0