# ADR-002: Bundle Wrapper Deployment Architecture **Date**: 2025-11-17 **Status**: ACCEPTED **Version**: 2.0 (Updated with hybrid NuShell + Bash fallback) **Author**: Architecture Review **Scope**: Hybrid runtime wrapper deployment for bundle installations --- ## Problem Statement **Question**: Should bundle installations create the same three-layer wrapper structure that development installations create? **Current State**: - **Development users** (`scripts/install-syntaxis.nu`): Get full wrapper infrastructure - Binaries renamed to `.real` - Bash wrappers at original locations - NuShell wrappers deployed to `~/.config/syntaxis/scripts/` - Result: Auto-config injection ✅ → Users type: `syntaxis-cli status` - **Bundle users** (`scripts/provisioning/install.sh`): Get direct binaries only - Binaries installed directly - No wrapper infrastructure - No config auto-injection - Result: Manual config flags ❌ → Users must type: `syntaxis-cli --config path status` **The Issue**: Inconsistent user experience between installation methods. --- ## Wrapper Architecture: Hybrid Design (NuShell + Bash Fallback) ### With NuShell Installed (Preferred): Three Layers **Layer 1: Bash Wrapper** ```bash ~/.local/bin/syntaxis-cli (300 bytes) ├─ Checks: Is NuShell available? ├─ If YES: Sets NU_LIB_DIRS="$HOME/.config/syntaxis/scripts" └─ Calls: nu "$HOME/.config/syntaxis/scripts/syntaxis-cli.nu" "$@" ``` **Layer 2: NuShell Wrapper** ```nushell ~/.config/syntaxis/scripts/syntaxis-cli.nu (2.2 KB) ├─ Searches: Config file locations ├─ Discovers: ~/.config/syntaxis/syntaxis-cli.toml ├─ Injects: --config ~/.config/syntaxis/syntaxis-cli.toml └─ Calls: ~/.local/bin/syntaxis-cli.real --config ... status ``` **Layer 3: Real Binary** ``` ~/.local/bin/syntaxis-cli.real (7.2 MB) └─ Actual compiled Rust binary ``` ### Without NuShell: Two Layers (Simplified) **Layer 1: Bash Wrapper (with inline config discovery)** ```bash ~/.local/bin/syntaxis-cli (300 bytes) ├─ Checks: Is NuShell available? ├─ If NO: Use bash-only config discovery ├─ Searches: Config in ~/.config/syntaxis/*, .syntaxis/, .project/, .coder/ ├─ If found: Injects --config flag └─ Calls: ~/.local/bin/syntaxis-cli.real --config status ``` **Layer 2: Real Binary** ``` ~/.local/bin/syntaxis-cli.real (7.2 MB) └─ Actual compiled Rust binary ``` ### User Experience ```bash $ syntaxis-cli status # Wrapper automatically injects --config # Clean, simple, no typing burden ``` --- ## Decision: ADD HYBRID WRAPPERS TO BUNDLE **Recommendation**: Bundle installations should create hybrid wrappers that work with or without NuShell. ### Rationale 1. **Self-Contained Bundle** - No hard dependency on NuShell - Works offline (no downloads required) - Fallback ensures functionality 2. **User Flexibility** - NuShell users get full features immediately - Non-NuShell users still get auto-config - User prompted to install NuShell (optional upgrade) 3. **Graceful Degradation** - With NuShell: Full three-layer architecture (best UX) - Without NuShell: Simple bash discovery (good UX) - Both modes provide auto-config injection 4. **Minimal Maintenance** - Only ~15 lines of bash fallback code - No library translation needed - NuShell libraries only used when available 5. **Daily UX Impact** - Users invoke 100s of times per day/week - Auto-config saves significant typing burden - Works regardless of NuShell availability --- ## Implementation Plan ### 1. Update `scripts/provisioning/install.sh` **Key functions added**: **a) Detect NuShell**: ```bash check_nushell() { if command -v nu &> /dev/null; then NUSHELL_VERSION=$(nu --version 2>/dev/null | head -1) return 0 else return 1 fi } ``` **b) Prompt user about NuShell**: ```bash prompt_nushell() { # Shows installation guide if NuShell not found # Offers user choice: continue or install NuShell # Non-blocking (continues with fallback if needed) } ``` **c) Create hybrid bash wrapper**: ```bash create_bash_wrapper() { local dest="$1" local binary_name=$(basename "$dest") # Create wrapper that: # 1. Checks if NuShell is available # 2a. If YES: use full three-layer architecture # 2b. If NO: use bash-only config discovery } ``` **d) Wrapper logic**: ```bash #!/bin/bash # Hybrid wrapper - tries NuShell first if command -v nu &>/dev/null; then # Full mode: NuShell + libraries export NU_LIB_DIRS="$HOME/.config/syntaxis/scripts" exec nu "$HOME/.config/syntaxis/scripts/${BINARY_NAME}.nu" "$@" fi # Fallback: Bash-only config discovery for cfg_path in \ "$HOME/.config/syntaxis/${BINARY_NAME}.toml" \ "$HOME/.config/syntaxis/config.toml" \ ".syntaxis/${BINARY_NAME}.toml"; do if [[ -f "$cfg_path" ]]; then exec "$REAL_BINARY" --config "$cfg_path" "$@" fi done # No config found exec "$REAL_BINARY" "$@" ``` ### 2. Deploy NuShell Wrapper Scripts **Add to `install.sh`**: ```bash deploy_wrapper_scripts() { local scripts_dir="./scripts" local config_scripts_dir="$HOME/.config/syntaxis/scripts" mkdir -p "$config_scripts_dir" # Deploy shared library cp "$scripts_dir/syntaxis-lib.nu" "$config_scripts_dir/" # Deploy binary-specific wrappers for binary in syntaxis-cli syntaxis-tui syntaxis-api; do cp "$scripts_dir/${binary}.nu" "$config_scripts_dir/" 2>/dev/null || true cp "$scripts_dir/${binary}-lib.nu" "$config_scripts_dir/" 2>/dev/null || true done chmod +x "$config_scripts_dir"/*.nu } ``` ### 3. Update `provisioning.toml` **Add wrapper scripts to artifacts**: ```toml [artifacts] # ... existing config ... # Wrapper scripts for auto-config injection wrapper_scripts = [ "scripts/syntaxis-lib.nu", "scripts/syntaxis-cli.nu", "scripts/syntaxis-cli-lib.nu", "scripts/syntaxis-tui.nu", "scripts/syntaxis-tui-lib.nu", "scripts/syntaxis-api.nu", "scripts/syntaxis-api-lib.nu", ] ``` ### 4. Update Bundle Structure **Result after installation**: ``` User's system after bundle installation: ~/.cargo/bin/ ├── syntaxis-cli ← Bash wrapper ├── syntaxis-cli.real ← Actual binary ├── syntaxis-tui ← Bash wrapper ├── syntaxis-tui.real ← Actual binary └── syntaxis-api ← Bash wrapper └── syntaxis-api.real ← Actual binary ~/.config/syntaxis/scripts/ ├── syntaxis-lib.nu ← Shared library ├── syntaxis-cli.nu ← NuShell wrapper ├── syntaxis-cli-lib.nu ← CLI utilities ├── syntaxis-tui.nu ← NuShell wrapper ├── syntaxis-tui-lib.nu ← TUI utilities ├── syntaxis-api.nu ← NuShell wrapper └── syntaxis-api-lib.nu ← API utilities ``` --- ## Technical Specifications ### Wrapper Scripts to Include | Script | Size | Purpose | |--------|------|---------| | `syntaxis-lib.nu` | 1.1 KB | Shared library (config discovery) | | `syntaxis-cli.nu` | 2.2 KB | CLI wrapper (auto-config injection) | | `syntaxis-cli-lib.nu` | 1.5 KB | CLI utilities | | `syntaxis-tui.nu` | 2.2 KB | TUI wrapper | | `syntaxis-tui-lib.nu` | 743 B | TUI utilities | | `syntaxis-api.nu` | 3.6 KB | API wrapper | | `syntaxis-api-lib.nu` | 2.2 KB | API utilities | | **Total** | ~13.5 KB | All wrapper infrastructure | ### Bundle Size Impact - **Before**: Binaries + configs + docs = ~9.2 MB - **After**: + wrapper scripts (~13.5 KB) = ~9.2 MB (negligible) ### Installation Steps 1. Extract bundle 2. Run `bash install.sh --interactive` - Installs binaries to `~/.local/bin/` (or custom prefix) - Deploys wrapper scripts to `~/.config/syntaxis/scripts/` - Renames binaries to `.real` - Creates bash wrappers at original locations 3. Run `bash setup-config.sh --interactive` - Creates configuration files --- ## Benefits ✅ **Users Don't Type `--config`** - Every invocation automatically injects config path - Saves millions of characters per year ✅ **Transparent** - Users see no difference from direct binary - Wrapper is invisible to end users ✅ **Flexible** - Config files can be in multiple locations - Wrapper discovers automatically ✅ **Consistent** - Same experience as development installation - Feature parity across installation methods ✅ **Maintainable** - Clear separation: wrapper scripts vs binaries - Easy to update wrappers without rebuilding binaries --- ## Trade-offs ### With NuShell (Full Mode) **Pros**: - ✅ Excellent user experience (no --config needed) - ✅ Advanced config discovery (multiple paths, precedence) - ✅ Full feature set available - ✅ Consistent with development installation **Cons**: - ⚠️ Startup overhead (~50ms from NuShell) - ⚠️ Requires NuShell to be installed - ⚠️ Slightly more complex ### Without NuShell (Simplified Mode) **Pros**: - ✅ No external dependencies - ✅ Works offline (self-contained) - ✅ Still provides auto-config injection - ✅ Simple bash-only fallback **Cons**: - ⚠️ Less advanced config discovery - ⚠️ Simplified version of full features - ⚠️ User prompted to install NuShell (optional) ### Overall Hybrid Approach **Pros**: - ✅ Self-contained bundle (no requirements) - ✅ Works for all users (NuShell or not) - ✅ Graceful degradation (best effort) - ✅ Minimal maintenance (only ~15 lines bash fallback) - ✅ User-aware (prompted to upgrade if desired) **Cons**: - ⚠️ Two code paths to test - ⚠️ Slightly more complexity in wrapper - ⚠️ NuShell libraries deployment (optional when not available) --- ## Risk Assessment ### Low Risk ✅ - Exact same code as development installation - NuShell is already required for development - Startup overhead is acceptable for CLI tools - Can always use `.real` binaries if needed --- ## Implementation Checklist - [ ] Modify `scripts/provisioning/install.sh` to create wrappers - [ ] Add `deploy_wrapper_scripts()` function to install.sh - [ ] Update `configs/provisioning.toml` to include wrapper scripts - [ ] Update `scripts/provisioning/pack.nu` to package wrapper scripts - [ ] Test bundle installation creates complete wrapper structure - [ ] Update documentation (docs/installation.md, README.md) - [ ] Rebuild bundle with wrapper support - [ ] Verify wrapper functionality post-install --- ## Comparison: With vs Without Wrappers ### Without Wrappers (Current Bundle) ```bash $ syntaxis-cli project list # User must provide --config flag every time $ syntaxis-cli --config ~/.config/syntaxis/syntaxis-cli.toml project list # Burden: 50+ characters per invocation # 100 invocations = 5,000+ characters of typing ``` ### With Wrappers (Proposed) ```bash $ syntaxis-cli project list # Wrapper injects --config automatically # Clean, simple, Unix-like experience # Burden: 0 additional typing # Users just type normal commands ``` --- ## Related Documentation - `docs/installation/WRAPPER_DESIGN.md` - Technical wrapper design - `scripts/install-syntaxis.nu` - Development installation with wrappers - `scripts/provisioning/install.sh` - Bundle installation (to be updated) --- ## Conclusion **Decision**: Implement full wrapper deployment in bundle installations. **Rationale**: - High value (users don't type --config) - Low complexity (existing code, ~14 KB) - Better user experience - Feature parity with development installation This approach aligns with SYNTAXIS philosophy of providing excellent, transparent tooling for developers and teams. --- **Status**: ACCEPTED - Ready for implementation