nushell-plugins/docs/architecture/plugin-exclusion-system.md
Jesús Pérez d9ef2f0d5b
Some checks failed
Build and Test / Validate Setup (push) Has been cancelled
Build and Test / Build (darwin-amd64) (push) Has been cancelled
Build and Test / Build (darwin-arm64) (push) Has been cancelled
Build and Test / Build (linux-amd64) (push) Has been cancelled
Build and Test / Build (windows-amd64) (push) Has been cancelled
Build and Test / Build (linux-arm64) (push) Has been cancelled
Build and Test / Security Audit (push) Has been cancelled
Build and Test / Package Results (push) Has been cancelled
Build and Test / Quality Gate (push) Has been cancelled
Nightly Build / Check for Changes (push) Has been cancelled
Nightly Build / Validate Setup (push) Has been cancelled
Nightly Build / Nightly Build (darwin-amd64) (push) Has been cancelled
Nightly Build / Nightly Build (darwin-arm64) (push) Has been cancelled
Nightly Build / Nightly Build (linux-amd64) (push) Has been cancelled
Nightly Build / Nightly Build (windows-amd64) (push) Has been cancelled
Nightly Build / Nightly Build (linux-arm64) (push) Has been cancelled
Nightly Build / Create Nightly Pre-release (push) Has been cancelled
Nightly Build / Notify Build Status (push) Has been cancelled
Nightly Build / Nightly Maintenance (push) Has been cancelled
chore: update all plugins to Nushell 0.111.0
- Bump all 18 plugins from 0.110.0 to 0.111.0
  - Update rust-toolchain.toml channel to 1.93.1 (nu 0.111.0 requires ≥1.91.1)

  Fixes:
  - interprocess pin =2.2.x → ^2.3.1 in nu_plugin_mcp, nu_plugin_nats, nu_plugin_typedialog
    (required by nu-plugin-core 0.111.0)
  - nu_plugin_typedialog: BackendType::Web initializer — add open_browser: false field
  - nu_plugin_auth: implement missing user_info_to_value helper referenced in tests

  Scripts:
  - update_all_plugins.nu: fix [package].version update on minor bumps; add [dev-dependencies]
    pass; add nu-plugin-test-support to managed crates
  - download_nushell.nu: rustup override unset before rm -rf on nushell dir replace;
    fix unclosed ) in string interpolation
2026-03-11 03:22:42 +00:00

14 KiB

Plugin Exclusion System (v1.0.0)\n\n## Overview\n\nThe Plugin Exclusion System is a configuration-driven mechanism that allows selective exclusion of plugins from distributions, collections, and installations while maintaining full availability for development, testing, and reference purposes.\n\nStatus: Implemented (2025-12-03)\nPurpose: Exclude reference/documentation plugins (like nu_plugin_example) from end-user distributions\n\n---\n\n## Architecture\n\n### Design Principle\n\nSingle Source of Truth: All plugin exclusions are centrally defined in etc/plugin_registry.toml, ensuring consistency across all distribution-related operations.\n\nplaintext\nplugin_registry.toml (source of truth)\n ↓\n ┌───┴────────────────────────────────────┐\n ↓ ↓\ncollect_full_binaries.nu create_distribution_packages.nu\n(collection operations) (packaging operations)\n ↓ ↓\ndistribution/ directories bin_archives/ packages\n\n\n### Configuration\n\n#### Plugin Registry Entry\n\nFile: etc/plugin_registry.toml\n\ntoml\n[distribution]\nexcluded_plugins = [\n "nu_plugin_example"\n]\nreason = "Reference/documentation plugin - excluded from distributions, installations, and collections. Still included in build and test for validation."\n\n\nStructure:\n\n- excluded_plugins (required): List of plugin names to exclude from distributions\n- reason (optional): Documentation of why plugins are excluded\n\nAdding New Exclusions:\n\ntoml\n[distribution]\nexcluded_plugins = [\n "nu_plugin_example",\n "nu_plugin_new_reference" # Add here\n]\n\n\n---\n\n## Implementation\n\n### 1. Collection System (scripts/collect_full_binaries.nu)\n\n#### Helper Function\n\nnu\ndef get_excluded_plugins []: nothing -> list<string> {\n try {\n let registry_path = "./etc/plugin_registry.toml"\n if not ($registry_path | path exists) {\n return []\n }\n\n let registry_content = open $registry_path\n let excluded = try {\n $registry_content.distribution.excluded_plugins\n } catch {\n []\n }\n\n return $excluded\n } catch {\n return []\n }\n}\n\n\nKey Features:\n\n- Reads exclusion list from registry\n- Graceful error handling (returns empty list if registry missing/malformed)\n- Non-blocking (collection continues even if registry unavailable)\n\n#### Workspace Plugins Filtering\n\nnu\ndef get_workspace_plugins_info [platform: string, use_release: bool, profile: string]: nothing -> list<record> {\n let excluded_plugins = (get_excluded_plugins)\n\n let workspace_plugins = [\n "nu_plugin_custom_values"\n "nu_plugin_example"\n "nu_plugin_formats"\n # ... other plugins\n ]\n\n # Filter out excluded plugins\n let available_plugins = $workspace_plugins | where { |p| $p not-in $excluded_plugins }\n\n # Process only available plugins\n for plugin in $available_plugins {\n # ... collection logic\n }\n}\n\n\n#### Custom Plugins Filtering\n\nnu\ndef get_custom_plugins_info [platform: string, use_release: bool, profile: string]: nothing -> list<record> {\n let excluded_plugins = (get_excluded_plugins)\n\n let plugin_dirs = (glob $"nu_plugin_*")\n | where ($it | path type) == "dir"\n | where ($it | path basename) != "nushell"\n | where { |p| ($p | path basename) not-in $excluded_plugins } # Filter excluded\n | each { |p| $p | path basename }\n\n # Process remaining plugins\n}\n\n\n### 2. Packaging System (scripts/create_distribution_packages.nu)\n\n#### Helper Function\n\nnu\ndef get_excluded_plugins_dist []: nothing -> list<string> {\n try {\n let registry_path = "./etc/plugin_registry.toml"\n if not ($registry_path | path exists) {\n return []\n }\n\n let registry_content = open $registry_path\n let excluded = try {\n $registry_content.distribution.excluded_plugins\n } catch {\n []\n }\n\n return $excluded\n } catch {\n return []\n }\n}\n\n\n#### Plugin Components Filtering\n\nnu\ndef get_plugin_components [platform: string, version: string] {\n let extension = get_binary_extension $platform\n let excluded_plugins = (get_excluded_plugins_dist)\n\n # Get custom plugins - skip excluded ones\n let custom_plugin_binaries = (\n glob "nu_plugin_*"\n | where ($it | path type) == "dir"\n | each {|plugin_dir|\n let plugin_name = ($plugin_dir | path basename)\n if $plugin_name in $excluded_plugins {\n null\n } else {\n # ... process plugin\n }\n }\n | compact\n )\n\n # Get workspace plugins - filter excluded\n let workspace_plugins = [\n "nu_plugin_custom_values"\n "nu_plugin_example"\n # ... other plugins\n ]\n\n let workspace_plugin_binaries = (\n $workspace_plugins\n | where { |p| $p not-in $excluded_plugins } # Filter excluded\n | each {|plugin_name|\n # ... process plugin\n }\n | compact\n )\n\n {\n binaries: ($custom_plugin_binaries | append $workspace_plugin_binaries)\n }\n}\n\n\n### 3. Installation Configuration (scripts/templates/default_config.nu)\n\n#### Auto-load Plugin List\n\nBefore:\n\nnu\nlet plugin_binaries = [\n "nu_plugin_clipboard"\n "nu_plugin_desktop_notifications"\n "nu_plugin_hashes"\n "nu_plugin_highlight"\n "nu_plugin_image"\n "nu_plugin_kcl"\n "nu_plugin_tera"\n "nu_plugin_custom_values"\n "nu_plugin_example" # ❌ Would be auto-loaded\n "nu_plugin_formats"\n # ...\n]\n\n\nAfter:\n\nnu\n# Auto-load common plugins if they're available\n# NOTE: nu_plugin_example is excluded from distributions - it's for reference and development only\nlet plugin_binaries = [\n "nu_plugin_clipboard"\n "nu_plugin_desktop_notifications"\n "nu_plugin_hashes"\n "nu_plugin_highlight"\n "nu_plugin_image"\n "nu_plugin_kcl"\n "nu_plugin_tera"\n "nu_plugin_custom_values"\n "nu_plugin_formats" # ✅ Auto-loaded (example removed)\n # ...\n]\n\n\n---\n\n## Behavior Matrix\n\n| Operation | Excluded Plugin | Included Plugin |\n|-----------|-----------------|-----------------|\n| just build | Built | Built |\n| just build-nushell | Built | Built |\n| just test | Tested | Tested |\n| just collect | Excluded | Collected |\n| just collect-full | Excluded | Collected |\n| just pack | Excluded | Packaged |\n| just pack-full | Excluded | Packaged |\n| Distribution Installation | Not auto-loaded | Auto-loaded |\n| Manual Reference Use | Available | Available |\n\n---\n\n## Use Cases\n\n### Use Case 1: Reference Plugin\n\nScenario: Plugin serves as a template/documentation reference but shouldn't ship with distributions\n\nConfiguration:\n\ntoml\n[distribution]\nexcluded_plugins = [\n "nu_plugin_example"\n]\nreason = "Template for plugin developers. Not intended for end users."\n\n\nResult:\n\n- Developers can still use it: ./nushell/target/release/nu_plugin_example\n- End-user distributions don't include it\n- Documentation can reference it as a learning resource\n\n### Use Case 2: Experimental Plugin\n\nScenario: Plugin is under development and not yet stable\n\nConfiguration:\n\ntoml\n[distribution]\nexcluded_plugins = [\n "nu_plugin_example",\n "nu_plugin_experimental"\n]\nreason = "Experimental features. Stable once API is finalized."\n\n\nResult:\n\n- Can be tested internally\n- Not distributed to users until ready\n- Easily re-enabled by removing from list\n\n### Use Case 3: Conditional Exclusion\n\nScenario: Plugin should only be excluded for specific use cases\n\nImplementation Note: The current system excludes globally. For conditional exclusion, extend the registry:\n\ntoml\n[distribution]\nexcluded_plugins = ["nu_plugin_example"]\n\n[distribution.profiles]\nenterprise = ["nu_plugin_example", "nu_plugin_dev_tools"]\nminimal = ["nu_plugin_example", "nu_plugin_kcl", "nu_plugin_tera"]\n\n\nThen update scripts to support profile-based filtering.\n\n---\n\n## Error Handling\n\n### Scenario: Registry File Missing\n\nBehavior: Scripts return empty exclusion list, all plugins included\n\nnu\nif not ($registry_path | path exists) {\n return [] # No exclusions\n}\n\n\nResult: Safe degradation - system works without registry\n\n### Scenario: Registry Parse Error\n\nBehavior: Catches exception, returns empty list\n\nnu\nlet excluded = try {\n $registry_content.distribution.excluded_plugins\n} catch {\n [] # If key missing or malformed\n}\n\n\nResult: Malformed registry doesn't break distribution process\n\n### Scenario: Invalid Plugin Name\n\nBehavior: Non-existent plugins in exclusion list are silently skipped\n\nnu\n| where { |p| $p not-in $excluded_plugins } # No match = included\n\n\nResult: Future-proofs against plugin renames or removals\n\n---\n\n## Integration Points\n\n### 1. Collection Workflow\n\nplaintext\njust collect\n ↓\ncollect_full_binaries.nu main\n ↓\nget_excluded_plugins() → registry.toml\n ↓\nget_workspace_plugins_info() → [filtered list]\nget_custom_plugins_info() → [filtered list]\n ↓\ndistribution/ (without excluded plugins)\n\n\n### 2. Packaging Workflow\n\nplaintext\njust pack-full\n ↓\ncreate_distribution_packages.nu main\n ↓\nget_excluded_plugins_dist() → registry.toml\n ↓\nget_plugin_components() → [filtered list]\n ↓\nbin_archives/ (without excluded plugins)\n\n\n### 3. Build Workflow\n\nplaintext\njust build (unchanged)\n ↓\nbuild_all.nu\n ↓\ncargo build (all plugins including excluded)\n ↓\ntarget/release/ (includes ALL plugins)\n\n\n### 4. Installation Workflow\n\nplaintext\ndistribution/platform/\n ↓\ndefault_config.nu (filters excluded at config level)\n ↓\nUser's Nushell config (excluded plugins not auto-loaded)\n\n\n---\n\n## Maintenance\n\n### Adding a Plugin to Exclusion List\n\n1. Update Registry:\n\nbash\n# Edit: etc/plugin_registry.toml\n[distribution]\nexcluded_plugins = [\n "nu_plugin_example",\n "nu_plugin_new_ref" # ← Add here\n]\n\n\n1. Optional: Update Default Config:\n\nbash\n# Edit: scripts/templates/default_config.nu\n# Add comment explaining why it's excluded\n\n\n1. Test:\n\nbash\njust collect # Should exclude both plugins\njust pack-full # Should package without both\njust build # Should still build both\n\n\n### Removing a Plugin from Exclusion List\n\n1. Update Registry:\n\nbash\n# Edit: etc/plugin_registry.toml\n[distribution]\nexcluded_plugins = [\n "nu_plugin_example" # ← Removed\n]\n\n\n1. Test:\n\nbash\njust collect # Should now include it\njust pack-full # Should now package it\n\n\n---\n\n## Files Modified\n\n| File | Changes | Type |\n|------|---------|------|\n| etc/plugin_registry.toml | Added [distribution] section | Config |\n| scripts/collect_full_binaries.nu | Added get_excluded_plugins(), updated workspace/custom filtering | Feature |\n| scripts/create_distribution_packages.nu | Added get_excluded_plugins_dist(), updated component filtering | Feature |\n| scripts/templates/default_config.nu | Removed excluded plugin from auto-load list | Config |\n\n---\n\n## Performance Impact\n\n- Collection: Negligible (single registry read, O(n) filtering where n = excluded count)\n- Packaging: Negligible (same as collection)\n- Build: None (excluded plugins still built)\n- Installation: None (config parsing is same cost)\n\n---\n\n## Future Enhancements\n\n1. Profile-Based Exclusion: Support different exclusion lists per distribution profile\n\n toml\n [distribution.profiles]\n enterprise = [...]\n minimal = [...]\n \n\n2. Conditional Compilation: Exclude from build based on feature flags\n\n rust\n #[cfg(feature = "include_example")]\n pub mod example;\n \n\n3. Deprecation Timeline: Mark plugins as deprecated with removal date\n\n toml\n [distribution.deprecated]\n "nu_plugin_old" = "2025-12-31" # Will be removed after date\n \n\n4. Exclusion Reasoning: Rich metadata about why plugins are excluded\n\n toml\n [distribution.exclusions."nu_plugin_example"]\n reason = "reference_plugin"\n since_version = "0.109.0"\n target_inclusion = "never" # or "1.0.0"\n \n\n---\n\n## References\n\n- Registry: etc/plugin_registry.toml\n- Collection Scripts: scripts/collect_full_binaries.nu\n- Packaging Scripts: scripts/create_distribution_packages.nu\n- Configuration: scripts/templates/default_config.nu\n- Build System: justfile, justfiles/build.just, scripts/build_all.nu\n\n---\n\n## Testing\n\n### Verification Checklist\n\n- [ ] Registry reads correctly: nu -c "open ./etc/plugin_registry.toml | get distribution.excluded_plugins"\n- [ ] Collection excludes: just collect && ls distribution/ | grep example (should be empty)\n- [ ] Packaging excludes: just pack-full && tar -tzf bin_archives/*.tar.gz | grep example (should be empty)\n- [ ] Build includes: just build-nushell && ls nushell/target/release/ | grep example (should exist)\n- [ ] Config doesn't auto-load: grep nu_plugin_example scripts/templates/default_config.nu (should not appear in plugin_binaries list)\n\n---\n\nVersion: 1.0.0\nLast Updated: 2025-12-03\nStatus: Stable