Skip to content

Activation and Deactivation

tonythethompson edited this page Jul 10, 2026 · 1 revision

Activation & Deactivation

Activation and Deactivation represent the bridge between Numan's inert package storage and the live Nushell environment. While Numan follows an "install is inert" principle—meaning that the install command only writes to the $NUMAN_ROOT directory—the activate and deactivate commands are the sole mechanisms permitted to modify Nushell integration state.

Architecture Overview

Numan manages two distinct "lanes" for activation: Plugins and Modules. These lanes are processed sequentially and are independently journaled to ensure crash recovery and state integrity. Activation is tied to a specific Nushell identity, defined by the executable's SHA-256 hash and version string. If the Nushell binary changes (e.g., after a system update), Numan detects "drift" and requires a refresh before further activation mutations can occur.

The Activation Flow

The following diagram illustrates the high-level logic used when a user executes the activate command.

flowchart TD
    Start[numan activate] --> Probe[Probe Nu Identity]
    Probe --> DriftCheck{Drift Detected?}
    DriftCheck -- Yes --> Fail[Error: numan init --refresh]
    DriftCheck -- No --> LoadLock[Load Lockfile]
    LoadLock --> Plan[Plan Plugin & Module Lanes]
    Plan --> Consent{User Consent?}
    Consent -- No --> Cancel[Abort]
    Consent -- Yes --> MutLock[Acquire Mutation Lock]
    MutLock --> JournalRec[Reconcile Journals]
    JournalRec --> Snapshot[Create State Snapshot]
    Snapshot --> PluginLane[Process Plugin Lane]
    PluginLane --> ModuleLane[Process Module Lane]
    ModuleLane --> Finalize[Release Lock & Print Summary]
Loading

Module Activation (The 13-Step Protocol)

Numan manages exactly one external file for modules: numan.nu located in the Nushell vendor-autoload directory. To ensure this file never causes Nushell to crash or hang, Numan employs a rigorous 13-step transaction protocol involving candidate generation and real Nushell validation.

Step-by-Step Transaction

  1. Acquire Mutation Lock: Prevents concurrent Numan processes from racing.
  2. Validate Nu Identity: Ensures the current environment matches cached paths.
  3. Verify Ownership: Checks the existing numan.nu for Numan's ownership marker.
  4. Generate Candidate: Creates a temporary file .<uuid>.candidate.tmp with use statements.
  5. Execute Validation: Runs nu -n <candidate> to verify syntax and path resolution.
  6. Snapshot Lockfile: Creates an immutable point-in-time backup.
  7. Write Journal (Prepared): Records intent to modify the external file.
  8. Replace File: Atomically renames the candidate to numan.nu.
  9. Write Journal (Replaced): Records that the external file has been updated.
  10. Update Lockfile: Adds ModuleActivation records to the authoritative lockfile.
  11. Update Autoload State: Writes autoload-state.json (a derived projection).
  12. Clear Journal: Deletes the recovery file.
  13. Release Lock: Ends the transaction.

Autoload State vs. Lockfile

Component Authority Level Purpose
Lockfile Ground Truth Definitive record of which packages are active.
Autoload State Derived Projection Fast-check cache of the current numan.nu contents.
Pending Autoload Recovery Journal Ensures atomic-like behavior across internal and external state.

Plugin Activation

Plugin activation uses the plugin add mechanism. Unlike modules, plugins are registered individually within Nushell's own internal registry. Numan manages this by setting environment variables (NUMAN_PLUGIN_BINARY and NUMAN_PLUGIN_CONFIG) and invoking Nushell to perform the registration.

sequenceDiagram
    participant CLI as numan CLI
    participant Journal as state/pending-activation.json
    participant Nu as Nushell Binary
    participant Lock as lockfile

    CLI->>Journal: Write Prepared Stage
    loop For each plugin
        CLI->>Nu: plugin add (via env vars)
        Nu-->>CLI: Success/Failure
        CLI->>Journal: Mark Registered/Failed
        CLI->>Lock: Update PluginActivation record
    end
    CLI->>Journal: Delete Journal
Loading

Deactivation Logic

Deactivation is currently supported primarily for modules. It follows a similar protocol to activation but involves either partial regeneration of the numan.nu file or its total deletion if no modules remain active.

Deactivation Scenarios

  • Partial Deactivation: If other modules remain active, Numan generates a new candidate file excluding the target modules, validates it, and replaces the live file.
  • Full Deactivation: If the target modules are the only ones active, Numan verifies ownership and deletes the numan.nu file entirely.

Data Structures

Module Activation Record

The ModuleActivation struct stores the specific environment metadata required to determine if an activation is still valid.

pub struct ModuleActivation {
    pub entry_path: String,
    pub import_mode: ModuleImportMode,
    pub vendor_autoload_dir: String,
    pub managed_file_path: String,
    pub nu_executable_sha256: String,
    pub nu_version: String,
    pub activated_at: String,
}

Pending Autoload (Journal)

This structure is used for crash recovery during module-autoload operations.

pub struct PendingAutoload {
    pub schema_version: u32,
    pub operation: AutoloadOperation,
    pub stage: AutoloadStage,
    pub nu_executable_sha256: String,
    pub nu_version: String,
    pub vendor_autoload_dir: String,
    pub managed_file_path: String,
    pub desired_active_module_ids: Vec<String>,
    pub created_at: String,
    // ... additional state for recovery
}

Conclusion

Activation and Deactivation provide the necessary safety guarantees for Numan's integration with Nushell. By utilizing advisory locks, journaled transactions, and same-filesystem atomic renames, Numan ensures that Nushell's startup behavior remains predictable even if a Numan process is interrupted or if the underlying system environment drifts.

Clone this wiki locally