Skip to content

Run startup command in interactive AND login shells#67

Open
jmcphers wants to merge 1 commit into
mainfrom
bugfix/shell-module-startup
Open

Run startup command in interactive AND login shells#67
jmcphers wants to merge 1 commit into
mainfrom
bugfix/shell-module-startup

Conversation

@jmcphers

@jmcphers jmcphers commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Relates to posit-dev/positron#13949

Summary

When a kernel is launched with a startup command or script, the supervisor ran it in a plain interactive shell. That was introduced in df17d2b to pick up environment setup users put in interactive rc files (~/.bashrc, ~/.zshrc).

The problem: a non-login interactive shell sources ~/.bashrc but not the system profile scripts (/etc/profile, /etc/profile.d/*). On many systems the module command (Lmod / Environment Modules) is only defined for login shells, via /etc/profile.d. So a module load ... startup command failed at launch with module: command not found, even though interpreter discovery (which uses a login shell) succeeded. bash's login and non-login-interactive startup-file sets are mutually exclusive, so a plain -i shell could never see the module setup.

This PR runs startup-command/script kernels as a shell that is both a login and an interactive shell (e.g. bash --login -i -c ..., zsh --login -i -c ...), so the environment picks up both the profile scripts (where module lives) and the interactive rc files (where users put PATH and tool init). Plain shell mode (StartupEnvironment::Shell, no command) is unchanged: still a non-interactive login shell.

Behavior by shell:

  • zsh: sources .zprofile (login) and .zshrc (interactive) unconditionally -- fully correct.
  • bash: sources the profile scripts plus ~/.bashrc via the standard ~/.profile/~/.bash_profile -> ~/.bashrc chain shipped by default on the major distributions. The -i flag also satisfies the case $- in *i*) interactivity guard at the top of ~/.bashrc (e.g. conda's init block), which a login-only shell would skip.
  • csh/tcsh: fall back to interactive-only (-i), since the -d login emulation can't combine with -c reliably.

This change fixes the module case at the supervisor layer (it also benefits any other startup command that depends on login-only init) and is complementary to the Positron-side fix in posit-dev/positron#13949, which makes the module startup command self-source its init script.

Caveat

A bash user who relies on ~/.bashrc-only setup via a startup command and whose ~/.bash_profile exists but does not source ~/.bashrc will no longer pick up ~/.bashrc here (a login shell reaches profile files, not ~/.bashrc, unless chained). This is uncommon -- such a setup also breaks the user's own login terminals -- and zsh is unaffected. Documented in the code.

Validation

  • cargo test -p kcserver --lib shell_wrapper -- new unit tests cover flag selection for login mode, login+interactive mode, and the csh fallback.
  • Manual: on a Linux system where module is defined only in login shells, configure an environment module for R or Python in Positron and start a session. Before this change the kernel fails with module: command not found; after, it starts.

@jmcphers jmcphers requested a review from samclark2015 June 8, 2026 19:18
@jmcphers jmcphers changed the title run interactive AND login shells Run startup command in interactive AND login shells Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant