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.
| Directory | Fork of | Changes |
|---|---|---|
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
-
env_to_strings()converts nushell's typed values to strings -
ENV_CONVERSIONSto_stringclosures handle typed vars (PATH as list) -
Strings injected into the bash subprocess via
exportcommands
Bash to Nu
-
After each command,
export -pcaptures all exported env vars -
Strings written to nushell's Stack via
add_env_var(Value::string(...)) -
Nushell's REPL automatically applies
from_stringconversions
Configuration
Shannon uses standard config locations — no custom config directory:
-
~/.bash_profile/~/.bashrc— bash login init (env vars injected into nushell at startup) -
~/.config/nushell/env.nu— nushell env setup -
~/.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