- Rust 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| assets | ||
| docs/agents | ||
| man | ||
| samples | ||
| src | ||
| tests | ||
| .gitignore | ||
| AGENTS.md | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| LICENSE-APACHE | ||
| LICENSE-MIT | ||
| README.md | ||
shellwhy
Explain which shell startup files are controlling a shell session.
shellwhy answers a practical dotfiles question: "why is my shell doing this?"
It inspects the current or requested shell mode, applies startup-file rules, safely parses obvious source statements, detects common shell tooling hooks, and reports what is inferred, possible, missing, skipped, or observed by trace mode.
Features
- Static startup-file rules for
bash,zsh, andfish. - Conservative fallback rules for
sh/dash,ksh/mksh,tcsh/csh, andnu. - Safe static parsing for obvious
source fileand. filestatements. - Detection for common shell tooling hooks, including
starship,oh-my-zsh,zinit,direnv,asdf,pyenv,nvm,fnm,fisher, andtide. - Human-readable, plain, and JSON output.
- Linux trace mode using
stracewhen available.
Install
From a checkout:
cargo install --path .
Or build a local release binary:
cargo build --release
./target/release/shellwhy --help
Usage
Inspect the current environment and infer the current shell:
shellwhy
Explain bash startup files for the current user:
shellwhy --shell bash
Explain zsh in a specific mode:
shellwhy --shell zsh --login --interactive
Print machine-readable output:
shellwhy --shell bash --json
shellwhy --shell fish --plain
Run Linux syscall tracing with strace and merge observed files:
shellwhy trace --shell fish
shellwhy trace --shell zsh --login --interactive
Explain why shell-startup certainty is hard:
shellwhy explain
Confidence Labels
shellwhy avoids pretending that static analysis can prove runtime shell behavior.
| Label | Meaning |
|---|---|
confirmed |
Observed by trace mode. |
inferred |
Follows from shell rules or a safely parsed source statement. |
possible |
Exists or is installed, but static mode cannot prove it loads. |
missing |
Expected or possible path does not exist. |
skipped |
Not loaded because mode or precedence rules exclude it. |
unknown |
There is not enough information. |
Static Mode
Static mode does not execute shell code. It can:
- Identify the target shell from
--shell,$SHELL, or parent process metadata. - Infer login, interactive, SSH, and terminal context from flags, process argv, TTY state, and environment.
- Apply startup rules for the selected shell and mode.
- Check whether startup files exist.
- Show files skipped because another file takes precedence, such as bash reading only the first existing
~/.bash_profile,~/.bash_login, or~/.profile. - Parse simple source statements without evaluating arbitrary shell code.
Static mode cannot prove conditional branches, dynamic paths, plugin-manager side effects, aliases, functions, exports, or PATH changes created at runtime.
Trace Mode
Trace mode launches a fresh target shell and observes file access through a platform backend.
Current backend:
- Linux:
strace
Planned backend:
- macOS:
dtrussorfs_usage
Trace mode may run user startup code because it starts the requested shell. Use static mode when you need non-invasive analysis.
Project Layout
src/detector.rs Shell detection and mode inference
src/rules/ Shell-specific startup rules
src/scanner.rs Filesystem checks and source expansion
src/source_parser.rs Safe parser for simple source statements
src/trace.rs Platform trace backend
src/reporter.rs Report assembly
src/formatter.rs Pretty, plain, and JSON output
Sample output files are in samples/.
Development
Run the test suite:
cargo test
Check formatting:
cargo fmt --check
Run Clippy:
cargo clippy --all-targets --all-features -- -D warnings
AI Use Citation
This repository was developed with AI assistance from OpenAI Codex. OpenAI describes Codex as a coding agent for building and shipping software with AI: https://openai.com/codex/.
AI-generated suggestions were reviewed by the maintainer before being accepted.
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT license (LICENSE-MIT)