# ADR-001: Wrapper Architecture Strategy **Date**: 2025-11-17 **Status**: PROPOSED **Author**: Architecture Review **Scope**: Installation and execution wrappers in SYNTAXIS --- ## Problem Statement SYNTAXIS uses two different wrapper patterns: 1. **Binary Execution Wrappers** (existing `install-syntaxis`): - Bash → NuShell → Rust (3 layers) - Handles config discovery and injection - Used by: `syntaxis-cli`, `syntaxis-tui`, `syntaxis-api` 2. **Installation Wrapper** (new `provision.sh`): - Bash orchestrator - Wraps `install.sh` + `setup-config.sh` - Used by: Bundle users during first-time installation **Question**: Should both patterns be used? Or should they follow different strategies? --- ## Analysis Framework ### Cost-Benefit Model for Wrappers ``` Wrapper Value = Frequency × (User Burden Saved) × Maintenance Complexity Where: - Frequency: How often is this called? (per session, per day, per lifetime) - User Burden: What pain does it eliminate? (typing, remembering steps, errors) - Complexity: How many layers/moving parts? (1 layer vs 3 layers) ``` --- ## Pattern 1: Binary Execution Wrappers (install-syntaxis) ### Current Implementation ``` Shell Invocation: syntaxis-cli status ↓ [Layer 1] Bash Wrapper (~212 bytes) └─ Sets: NU_LIB_DIRS="$HOME/.config/syntaxis/scripts" └─ Calls: nu "$HOME/.config/syntaxis/scripts/syntaxis-cli.nu" "status" ↓ [Layer 2] NuShell Wrapper (~2.2 KB) └─ Imports: syntaxis-lib.nu, syntaxis-cli-lib.nu └─ Discovers: Config file location └─ Injects: --config flag automatically └─ Calls: ~/.cargo/bin/syntaxis-cli.real --config ~/.config/syntaxis/config.toml status ↓ [Layer 3] Real Binary (7.2 MB) └─ Executes: With config path already provided ``` ### Why This Pattern? #### Without wrapper: ```bash # Every single invocation requires: $ syntaxis-cli --config ~/.config/syntaxis/config.toml status $ syntaxis-cli --config ~/.config/syntaxis/config.toml project list $ syntaxis-cli --config ~/.config/syntaxis/config.toml task create "name" # ... repeated 100s of times per day ``` **User Experience Problem**: - ❌ Users must remember config path - ❌ Config path is long and error-prone - ❌ Repetitive typing (every invocation) - ❌ Non-obvious that `--config` is required #### With wrapper: ```bash # Clean, simple invocations: $ syntaxis-cli status $ syntaxis-cli project list $ syntaxis-cli task create "name" # Config is automatic! ``` **User Experience Solution**: - ✅ Config path is invisible - ✅ Users follow Unix conventions - ✅ No typing overhead - ✅ Feels like a normal CLI tool ### Wrapper Value Calculation ``` Frequency: ~100 invocations per active session = Multiple times per hour, thousands per week User Burden Saved: - Per invocation: ~50 characters of typing - Per session: ~5,000 characters typed - Per year: ~2.6 million characters saved - Mental load: No need to remember config path Maintenance Complexity: 3 layers - But: Stable (rarely changed) - And: All in scripts (easy to modify) - Risk: Moderate (can bypass via .real) VERDICT: Value >> Complexity Cost RECOMMENDATION: KEEP THIS PATTERN ✅ ``` ### Existing File Locations ``` Installation Script: scripts/install-syntaxis (bash wrapper) scripts/install-syntaxis.nu (NuShell orchestrator) Deployed Wrappers: ~/.cargo/bin/syntaxis-cli (bash wrapper) ~/.cargo/bin/syntaxis-tui (bash wrapper) ~/.cargo/bin/syntaxis-api (bash wrapper) NuShell Wrappers: ~/.config/syntaxis/scripts/syntaxis-cli.nu (2.2 KB) ~/.config/syntaxis/scripts/syntaxis-tui.nu (2.2 KB) ~/.config/syntaxis/scripts/syntaxis-api.nu (3.6 KB) Shared Libraries: ~/.config/syntaxis/scripts/syntaxis-lib.nu (1.1 KB) ~/.config/syntaxis/scripts/syntaxis-cli-lib.nu (1.5 KB) ~/.config/syntaxis/scripts/syntaxis-tui-lib.nu (743 B) ~/.config/syntaxis/scripts/syntaxis-api-lib.nu (2.2 KB) Real Binaries: ~/.cargo/bin/syntaxis-cli.real (7.2 MB) ~/.cargo/bin/syntaxis-tui.real (3.9 MB) ~/.cargo/bin/syntaxis-api.real (8.3 MB) ``` --- ## Pattern 2: Installation Wrapper (provision.sh) ### Current Implementation ``` User: ./provision full ↓ [Layer 1] Bash Wrapper (provision.sh) └─ Detects: Shell availability (bash/zsh/NuShell) └─ Offers: Interactive menu OR one-step install └─ Orchestrates: install.sh → setup-config.sh └─ Calls: Either install or install + config ↓ [Layer 2A] Install Script (install.sh) └─ Installs: Binaries to ~/.local/bin/ └─ Updates: Shell PATH └─ Creates: Data directories ↓ [Layer 2B] Config Script (setup-config.sh) └─ Creates: TOML configs └─ Interactive: Prompts user for options └─ Deploys: Configs to ~/.config/syntaxis/ ``` ### Why This Pattern Was Created? **Intended Value**: 1. Make installation easier for beginners 2. One command instead of two 3. Guided interactive experience **Reality Check**: - Users run installer: **Once** (during first installation) - Users run binaries: **100s of times** (during normal use) ### Wrapper Value Calculation ``` Frequency: ~1 invocation per user = Only once during initial setup = Not multiple times per session User Burden Saved: - Per user: Saves 1 command typing (~50 characters) - Per year: ~50 characters saved (one time!) - Mental load: Not a problem (one-time activity) Maintenance Complexity: 2+ layers - Scripts call other scripts - PATH updates, permission handling, error recovery - Three different code paths (install only, config only, both) - Need to handle shell detection and options User Confusion: - "Which command should I use?" - install.sh or provision.sh? - provision install vs provision config vs provision full? - Documentation burden (explain 3 paths) VERDICT: Value << Complexity Cost RECOMMENDATION: REMOVE THIS PATTERN ❌ ``` ### Why This Pattern Is Problematic #### 1. One-Time Usage - Wrapper is called **once** during entire user lifetime - Binary wrappers are called **100s of times** per day - One-time benefit doesn't justify ongoing complexity #### 2. Confusion ``` Bundle contains: provision.sh ← Is this the way? install.sh ← Or this? setup-config.sh ← Or this? Users think: "Which command do I run?" "What's the difference?" "Which one is recommended?" ``` **Documentation Burden**: Must explain 3 approaches instead of 1 #### 3. Not Optional = Misleading ``` Current Status: provision.sh is marked "optional" BUT it's included in bundle BUT its necessity is unclear BUT install.sh works independently Result: Confusing, not truly optional ``` #### 4. Maintenance Burden ``` Code Paths to Test: Path 1: provision full (both steps) Path 2: provision install (binaries only) Path 3: provision config (config only) Path 4: bash install.sh (direct script) Path 5: bash setup-config.sh (direct script) Path 6: Manual (copy files) (user DIY) Testing Matrix: × 3 shells (bash, zsh, NuShell) × 4 platforms (Linux, macOS x2, Windows) × Multiple scenarios = Significant test burden for one-time use ``` #### 5. Violates SYNTAXIS Philosophy From CLAUDE.md: - ✅ "Modular with features to add or avoid" - ✅ "No unnecessary complexity" - ✅ "Users understand what's happening" Wrapper violates: - ❌ Not modular (orchestrates other scripts) - ❌ Unnecessary complexity (for one-time use) - ❌ Less transparent (abstraction not needed) --- ## Comparison: Binary Wrappers vs Installation Wrapper | Aspect | Binary Wrappers | Installation Wrapper | |--------|-----------------|----------------------| | **Frequency** | 100s per day | Once per lifetime | | **User Pain** | Config path typing (repetitive) | Two commands to type (one-time) | | **Value/Complexity** | High | Low | | **Justification** | Strong | Weak | | **Maintenance** | Stable/low | Medium/scattered | | **Transparency** | Can bypass via .real | No escape hatch | | **Philosophy** | Transparent execution | Abstraction | --- ## Decision Criteria ### When Wrappers Are Justified ``` ✅ Wrappers are justified when: Frequency × User Burden > Maintenance Complexity Cost Example: Binary wrappers - Frequency: 100s/day - User Burden: 50 chars/invocation - Result: Worth the 3 layers ``` ### When Wrappers Are NOT Justified ``` ❌ Wrappers are NOT justified when: Frequency × User Burden < Maintenance Complexity Cost Example: Installation wrapper - Frequency: 1x lifetime - User Burden: 50 chars once - Result: Not worth the orchestration ``` --- ## Recommendation ### For Binary Execution: KEEP Wrapper Pattern **Decision**: Keep `install-syntaxis` wrapper pattern (Bash → NuShell → Rust) **Rationale**: - ✅ Users don't want to type `--config path` 100s of times per day - ✅ Config discovery is complex (multiple locations, precedence) - ✅ Pattern is battle-tested and stable - ✅ Complexity is justified by frequency of use - ✅ Transparent to end users (no perceived overhead) **Action Items**: None - keep as-is --- ### For Installation: REMOVE Wrapper Pattern **Decision**: Remove `provision.sh` wrapper, use direct scripts only **Rationale**: - ❌ Users call installer once, not repeatedly - ❌ Wrapper adds unnecessary orchestration - ❌ Two clear scripts are simpler than three options - ❌ Violates "no unnecessary complexity" principle - ❌ Maintenance burden not justified for one-time use **Better Approach**: ```bash # Bundle contains only: install.sh ← Install binaries setup-config.sh ← Configure # Users follow two-step process: bash install.sh --interactive bash setup-config.sh --interactive # Simple, clear, transparent, Unix-way ``` **Benefits**: - ✅ No confusion (only 1 recommended path) - ✅ Less code to maintain - ✅ Clear sequence (install → config) - ✅ User understands each step - ✅ Easy to debug (direct scripts) - ✅ Follows Unix philosophy (one tool per job) **Action Items**: 1. Remove `scripts/provisioning/provision.sh` 2. Remove from `configs/provisioning.toml` artifacts.scripts array 3. Update `docs/installation.md` to show two-step process 4. Update `BUNDLE_README.md` to show simple sequence --- ## Trade-offs ### Keeping Binary Wrappers **Pros**: - Excellent user experience (no --config needed) - Justified by frequency (100s per day) - Config discovery is complex (needs orchestration) - Transparent (users don't notice) **Cons**: - More complex architecture - Requires both bash and NuShell - Adds startup overhead (~50ms) - More moving parts to understand ### Removing Installation Wrapper **Pros**: - Simpler (fewer scripts) - Clearer (no menu confusion) - More transparent (users understand each step) - Lower maintenance burden **Cons**: - Two commands instead of one - Users might forget second step (but unlikely - one-time setup) - No guided experience (but not needed - simple process) --- ## Implementation ### Phase 1: Decision **Status**: APPROVED ### Phase 2: Code Cleanup ```bash # Remove wrapper rm scripts/provisioning/provision.sh # Update config # Edit: configs/provisioning.toml # Remove: "scripts/provisioning/provision.sh" from artifacts.scripts array # Update documentation # Edit: docs/docs/installation.md - show two-step process # Edit: docs/BUNDLE_README.md - update quick start # Delete: docs/BUNDLE_DOCS_GUIDE.md references to provision ``` ### Phase 3: Update Bundle ```bash # Rebuild bundle nu scripts/provisioning/pack.nu # Verify changes tar -tzf dist/syntaxis-v0.1.0-*.tar.gz | grep -E '(install|setup|provision)' # Should show only: install.sh, install.nu, setup-config.sh # Should NOT show: provision.sh ``` ### Phase 4: Verification ```bash # Test installation workflow tar -xzf dist/syntaxis-v0.1.0-*.tar.gz cd syntaxis-v0.1.0-* # Step 1: Install bash install.sh --interactive # Step 2: Configure bash setup-config.sh --interactive # Verify syntaxis-cli --version ``` --- ## Risk Assessment ### Low Risk - ✅ Removing optional wrapper - ✅ Direct scripts are proven to work - ✅ No impact on binary wrappers - ✅ Clear documentation available ### Mitigation - Document two-step process clearly - Include both scripts in bundle (proven, working) - Test complete installation flow - Update all user-facing documentation --- ## Future Considerations ### If Installation Complexity Grows If future bundle setups become complex: - Consider wrapper again - But only if frequency or complexity increases - Apply same cost-benefit analysis ### Wrapper Pattern Elsewhere If other tools need wrappers: - Apply same framework - Justify by frequency × burden vs complexity - Transparency is key --- ## Appendix: Real-World Example ### Scenario: New User Installs SYNTAXIS **With Wrapper (Current)**: ```bash $ cd /tmp/bundle $ ./provision full # Menu appears, user selects options # Both install and configure run # Done! ``` **Without Wrapper (Proposed)**: ```bash $ cd /tmp/bundle $ bash install.sh --interactive # User prompted for installation options # Binaries installed # Done with step 1 $ bash setup-config.sh --interactive # User prompted for configuration # Configs created # Done with step 2 ``` **Difference**: - Wrapper: ~5 seconds (one command, orchestrated) - Direct: ~10 seconds (two commands, sequential) - **Complexity added**: ~5 seconds saved, once per lifetime - **Complexity removed**: Eliminates 100+ lines of code, maintenance **Clear winner**: Remove wrapper --- ## Conclusion ### Binary Execution Wrappers: KEEP ✅ - **Value**: Users invoke 100s of times per day - **Problem Solved**: Automatic config injection (major UX improvement) - **Complexity**: Justified and battle-tested ### Installation Wrapper: REMOVE ❌ - **Value**: Users invoke once per lifetime - **Problem Solved**: Saves one command (minor UX improvement) - **Complexity**: Not justified by benefit **Philosophy**: Wrappers should **enable frequent workflows**, not orchestrate **one-time procedures**. --- **Recommendation**: Implement Phase 2-4 cleanup to simplify bundle provisioning system. --- **Status**: READY FOR DECISION