Shannon logo Shannon

Architecture

This document explains how shannon works under the hood.

Shannon IS Nushell

Shannon copies the nushell binary source code (~4,600 lines) and adds mode dispatch for bash (via a persistent bash subprocess). This gives shannon all nushell features for free: terminal ownership, process groups, job control, signal handling, multiline editing, completions, hooks, plugins, and more.

Mode Dispatch

Shannon has two modes, toggled via Shift+Tab:

  • nu — nushell's native evaluation (default)
  • bash — bash commands via a persistent bash subprocess

The mode is stored in $env.SHANNON_MODE. When the mode is "nu", commands go through nushell's parser and evaluator as normal. When the mode is "bash", a ModeDispatcher trait intercepts the command in loop_iteration() and routes it to the bash subprocess.

ModeDispatcher Trait

Defined in nu-cli:

pub trait ModeDispatcher: Send {
    fn execute(
        &mut self,
        mode: &str,
        command: &str,
        env_vars: HashMap<String, String>,
        cwd: PathBuf,
    ) -> ModeResult;
}

The dispatcher receives string env vars (converted from nushell's typed values via env_to_strings()) and returns strings. Nushell's REPL writes them back to the Stack. The dispatcher never touches nushell internals directly.

Merged Dependencies

Nushell and reedline source is merged directly into the repo with full git history (via git subtree add). Shannon uses path deps. No crates.io publishing needed.

DirectoryFork ofChanges
nushell/ nushell/nushell ModeDispatcher, BashHighlighter, Shift+Tab, config dir
reedline/ nushell/reedline No code changes

Upstream sync: git subtree pull --prefix nushell upstream-nushell main

Environment Propagation

When switching modes, all exported environment variables and the cwd are preserved:

Nu to Bash

  1. env_to_strings() converts nushell's typed values to strings
  2. ENV_CONVERSIONS to_string closures handle typed vars (PATH as list)
  3. Strings injected into the bash subprocess via export commands

Bash to Nu

  1. After each command, export -p captures all exported env vars
  2. Strings written to nushell's Stack via add_env_var(Value::string(...))
  3. Nushell's REPL automatically applies from_string conversions

Configuration

Shannon uses standard config locations — no custom config directory:

  1. ~/.bash_profile / ~/.bashrc — bash login init (env vars injected into nushell at startup)
  2. ~/.config/nushell/env.nu — nushell env setup
  3. ~/.config/nushell/config.nu — nushell config (keybindings, colors, hooks)

The bash subprocess starts with bash --login, loading the user's standard bash config. Shannon adds no custom configuration — nushell's config.nu handles everything.

Syntax Highlighting

Each mode has its own highlighter, rebuilt every REPL iteration:

  • Nu mode: NuHighlighter (nushell's native highlighter)
  • Bash mode: BashHighlighter (tree-sitter-bash, colors from nushell config)

Source Code Layout

Copied from nushell binary (startup, terminal, signals):

main.rs, run.rs, command.rs, command_context.rs, config_files.rs, signals.rs, terminal.rs, logger.rs, ide.rs, experimental_options.rs, test_bins.rs

Shannon-specific (engines and dispatch):

dispatcher.rs, bash_process.rs, shell_engine.rs, shell.rs, executor.rs