Skip to content

feat: run shell commands through the detected user shell - #21

Merged
wowi42 merged 2 commits into
mainfrom
feat/detect-user-shell
Sep 29, 2026
Merged

wowi42 merged 2 commits into
mainfrom
feat/detect-user-shell

Conversation

@wowi42

@wowi42 wowi42 commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator

What

lecode executed shell commands through hardcoded shells — the agent's bash tool used /bin/sh -c, and the interactive !cmd / !!cmd shell-out used bash -c — so commands ran without the user's shell environment. Both now detect and use the user's shell.

How

  • New extras/shell.py: user_shell() resolves $SHELL via shutil.which (accepts absolute paths and bare names), falling back to /bin/sh when $SHELL is unset, empty, missing, or not executable — i.e. the previous behavior is the fallback
  • agent/tools/bash.py: BashTool resolves the shell at construction (shell= param for injection) and _run_shell executes it; background shell tasks inherit the shell since they run through _run_shell
  • The tool description names the resolved shell (Run a shell command (/bin/zsh -c)…) so the model can adapt its syntax (e.g. fish vs POSIX)
  • tui/app.py: !cmd / !!cmd run through user_shell() -c

Deliberately unchanged: hooks keep their documented /bin/sh -c contract (docs/hooks.md), and loop mode's configured command still runs via bash.

Tests

  • New tests/test_shell.py: unset/empty/missing/non-executable $SHELL → /bin/sh; absolute path used; bare name resolved on PATH
  • test_tool_bash.py: the tool runs commands through $SHELL -c (pinned with /bin/echo, which prints its argv) and the description names the detected shell
  • test_tui_app.py: !cmd uses the detected shell
  • Verified end-to-end with SHELL=/bin/zsh: description reads /bin/zsh -c, $0 and $ZSH_VERSION confirm zsh executes the command

The bash tool hardcoded /bin/sh -c and the interactive !cmd/!!cmd
shell-out hardcoded bash -c, so commands ran without the user's shell
environment. Both now resolve the shell via the new
extras/shell.user_shell(): $SHELL when it points at an executable
(absolute or on PATH), /bin/sh otherwise — the previous behavior. The
tool description names the resolved shell so the model adapts its
syntax, and background tasks inherit the shell through _run_shell.
Hooks keep their documented /bin/sh -c contract.
# Conflicts:
#	src/lecode/agent/tools/bash.py
@wowi42
wowi42 merged commit d7890eb into main Sep 29, 2026
4 checks passed
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