Package Activation & Deactivation
Relevant source files
The following files were used as context for generating this wiki page:
Package activation and deactivation in Numan constitute the primary interface between the package manager and the Nushell environment. While the installation process is intentionally inert to ensure system stability, activation is the explicit step that registers plugins with Nushell's plugin registry or configures modules via managed vendor autoload files.
This system is designed around the principle of scoped activation, ensuring that plugins and modules are only considered "active" if they match the specific Nushell executable hash, version, and configuration paths detected during the initialization process. This isolation prevents breakage when multiple versions of Nushell are present on a single system.
Sources: AGENTS.md:58-61, README.md:14-16
Architecture and Core Principles
The activation system operates on two distinct "lanes" based on package type: Plugins and Modules. Both lanes utilize a journaled transaction system to ensure crash recovery and maintain the lockfile as the single source of truth.
System Invariants
- Inert Installs:
numan installnever modifies Nushell's state; onlyactivateanddeactivatecommands touch Nushell integration. - Lockfile Authority: The
lockfileis the authoritative record of activation; derived files (likeautoload-state.json) are mere fast-check projections. - Mutation Locking: All activation changes must acquire an advisory mutation lock to prevent concurrent destructive operations.
- Atomic State Transitions: State files and journals are updated using atomic writes to prevent partial-write corruption.
Sources: AGENTS.md:142-154, src/cmd/deactivate.rs:94-118
Activation Flow
The following diagram illustrates the high-level flow of an activation/deactivation request:
The system ensures that any interrupted process can be reconciled by checking journals under state/ before proceeding with new mutations.
Sources: src/cmd/deactivate.rs:94-140, AGENTS.md:151-158
Module Activation (Vendor Autoload)
Numan manages Nushell modules by maintaining a single file located at <vendor-autoload-dir>/numan.nu. This file contains use statements for all active modules.
The Autoload Transaction
Module activation follows a strict multi-step process to ensure that the generated Nushell script is valid before it is applied.
| Step | Action | Description |
|---|---|---|
| 1 | Entry Resolution | Validates that module entry points exist, are .nu files, and reside within the managed Numan root. |
| 2 | Content Generation | Renders deterministic use statements with proper path escaping for the target OS. |
| 3 | Candidate Writing | Writes a temporary .candidate.tmp file to the autoload directory. |
| 4 | Validation | Executes nu -n <candidate> to verify syntax without loading existing user config. |
| 5 | Atomic Replacement | Moves the validated candidate over the live numan.nu file. |
Sources: src/nu/autoload.rs:10-28, src/cmd/deactivate.rs:645-748
Autoload Implementation Details
The system uses the OWNERSHIP_MARKER header to identify files it manages. It will refuse to overwrite any file in the autoload directory that does not contain this marker.
// src/nu/autoload.rs:163-176
pub fn render_use_statement(path: &Path, mode: &ModuleImportMode) -> Result<String> {
let path_str = path.to_str().context("...")?;
let escaped = path_str.replace('\\', "\\\\").replace('"', "\\\"");
let stmt = match mode {
ModuleImportMode::Module => format!("use \"{escaped}\""),
ModuleImportMode::All => format!("use \"{escaped}\" *"),
};
Ok(stmt)
}
Sources: src/nu/autoload.rs:163-176, src/nu/autoload.rs:365-374
Plugin Activation (Registry Integration)
Plugin activation involves interacting with Nushell's internal plugin registry. Unlike modules, which are managed via a text file, plugins are registered by invoking the Nushell binary itself.
Scoped Identity
A plugin is only considered active for the specific environment in which it was registered. Numan tracks this using a PluginActivation struct.
| Field | Description |
|---|---|
nu_executable_sha256 | Hash of the nu binary used during activation. |
nu_version | The specific version of Nushell. |
plugin_registry_path | The path to the Nushell plugins.msgpackz (or similar) file. |
Sources: AGENTS.md:151-154, src/cmd/deactivate.rs:434-444
Plugin Deactivation Journaling
Deactivation is handled via the PendingPluginDeactivate journal. This ensures that if the plugin rm command fails or the process is killed, the system knows the plugin is in a partially unregistered state.
Activation Constraints and Mutation Gates
Numan implements safety "gates" to prevent users from accidentally breaking their environment.
Active Plugin Mutation Gate (Issue #22)
To prevent instability, Numan refuses to remove or update a package if it has an active plugin activation record.
- Remove: Users must run
numan deactivate <pkg>beforenuman remove <pkg>. The--forceflag onremovebypasses module activation checks but cannot bypass plugin activation checks. - Update: Active-plugin updates are "fail-closed." They are only permitted if the user explicitly opts in by setting the environment variable
NUMAN_ENABLE_ACTIVE_PLUGIN_MUTATION=1.
Sources: src/cmd/remove.rs:109-114, src/util/hints.rs:142-166, src/cmd/deactivate.rs:592-595
Nu Identity Drift
The validate_drift() function is called before activation or partial deactivation. If the current Nushell executable or version does not match the cached NuPaths, the operation is aborted. This prevents registering plugins into a registry intended for a different Nushell version.
Sources: src/cmd/deactivate.rs:114-119, src/util/hints.rs:10-15
Summary
The activation and deactivation system in Numan provides a robust, journaled mechanism for integrating packages into Nushell. By separating the installation of immutable payloads from the activation of environment-specific integrations, Numan ensures that changes to the shell environment are explicit, validated, and recoverable. The use of scoped identities and mutation gates further protects the user's environment from inconsistent states during Nushell upgrades or concurrent package operations.