Shell

Shell#

The assistant can execute shell commands with bash by outputting code blocks with shell as the language.

Configuration:

GPTME_SHELL_TIMEOUT: Environment variable to configure command timeout (set before starting gptme)

  • Set to a number (e.g., 30) for timeout in seconds

  • Set to 0 to disable timeout

  • Invalid values default to 1200 seconds (20 minutes)

  • If not set, defaults to 1200 seconds (20 minutes)

GPTME_SHELL_MEMORY_LIMIT: Optional per-shell address-space ceiling (POSIX only,

off by default). Accepts a plain byte count or a binary suffix (e.g. “512M”, “1G”). Applies to the persistent shell and any command it runs via ulimit -v, so a runaway build fails with an allocation error instead of stalling the session.

GPTME_SHELL_TRUNC_PRE_TOKENS / GPTME_SHELL_TRUNC_POST_TOKENS: Override the head/tail token budget for stdout truncation. Defaults: 2000 / 8000. GPTME_SHELL_TRUNC_STDERR_PRE_TOKENS / GPTME_SHELL_TRUNC_STDERR_POST_TOKENS: Same overrides for stderr. Defaults: 2000 / 2000. Lowering these makes the truncation path fire on smaller outputs, which surfaces savings telemetry in context-savings.jsonl and the /context command. Invalid values fall back to defaults.

GPTME_SHELL_MAX_OUTPUT_BYTES: Hard cap on the total bytes (stdout + stderr

combined) captured into the in-process buffer before the subprocess is killed and the output is truncated. Accepts a plain byte count or a binary suffix (e.g. “32M”, “1G”). Default: 32 MiB. This prevents a runaway cat of a multi-GiB file from exhausting gptme’s RSS. The process receives SIGTERM then SIGKILL; the returned output contains a [output truncated at N MiB, process killed] marker. Token-level truncation (GPTME_SHELL_TRUNC_*) is applied on top as a second stage.

Instructions

The given command will be executed in a stateful bash shell.
The shell tool will respond with the output of the execution.

These programs are available, among others:
- apt-get
- docker
- git
- hyperfine
- pandoc

### When to use the shell

Use the shell to inspect the workspace, search files, check git state, or run
existing commands and tests. Prefer the repo over answering from memory.

### Background Jobs

For long-running commands (dev servers, builds):
- `bg <command>` - start, returns job ID
- `jobs` - list jobs
- `output <id>` - accumulated output
- `output <id> --new` - unread output only; poll while waiting for a log line
- `wait <id> [timeout]` - wait for completion; timeout leaves the job running
- `kill <id>` - terminate

Avoids blocking on commands like `npm run dev` that run indefinitely.

Examples

User
list the current directory
Assistant
To list the files in the current directory, use `ls`:
shell
ls
System
Ran command: `ls`
`stdout
file1.txt
file2.txt
`

The assistant can learn context by exploring the filesystem

User
learn about the project
Assistant
Lets start by checking the files
shell
git ls-files
System
`stdout
README.md
main.py
`
Assistant
Now lets check the README
shell
cat README.md
System
`stdout
(contents of README.md)
`
Assistant
Now we check main.py
shell
cat main.py
System
`stdout
(contents of main.py)
`
Assistant
The project is...

Create vue project

User
Create a new vue project with typescript and pinia named fancy-project
Assistant
Sure! Let's create a new vue project with TypeScript and Pinia named fancy-project:
shell
npm init vue@latest fancy-project --yes -- --typescript --pinia
System
`stdout
> npx
> create-vue

Vue.js - The Progressive JavaScript Framework

Scaffolding project in ./fancy-project...
`

Proper quoting for complex content

User
add a comment with backticks and special characters
Assistant
When passing complex content with special characters, use single quotes to prevent shell interpretation:
shell
echo 'Content with `backticks` and $variables that should not be interpreted' > example.txt

Background jobs for long-running commands

User
start a dev server
Assistant
I'll start the dev server as a background job so it doesn't block:
shell
bg npm run dev
System
Started background job **#1**: `npm run dev`
>
> Use these commands to manage it:
> - `jobs` - List all background jobs
> - `output 1` - Show output from job #1
> - `wait 1 60s` - Wait up to 60 seconds for job #1
> - `kill 1` - Terminate job #1
User
check the server output
Assistant
Let me check the output from the background job:
shell
output 1
System
**Job #1** - Running (45.2s)
Command: `npm run dev`
>
> ```stdout
> > project@1.0.0 dev
> > vite
>
> VITE v5.0.0  ready in 300 ms
>
> ➜  Local:   http://localhost:5173/
> ```
User
stop the server
Assistant
I'll terminate the background job:
shell
kill 1
System
Terminated job #1: `npm run dev`
gptme.tools.shell.close_conversation_shell(conversation_id: str) None

Close and remove the shell session for a conversation.

Called by the SESSION_END hook to clean up shell file descriptors when a conversation’s last session is removed.

gptme.tools.shell.execute_shell(code: str | None, args: list[str] | None, kwargs: dict[str, str] | None) Generator[Message, None, None]

Executes a shell command and returns the output.

gptme.tools.shell.execute_shell_impl(cmd: str, logdir: Path | None, timeout: float | None = None) Generator[Message, None, None]

Execute shell command and format output.

gptme.tools.shell.get_shell() ShellSession

Get the shell session for the current context, creating it if necessary.

Uses ContextVar to provide context-local state, allowing each conversation to have its own shell session with independent working directory.

In server contexts (where current_conversation_id is set), also registers the shell in a conversation-level registry for cleanup via SESSION_END hooks.

gptme.tools.shell.get_shell_command(code: str | None, args: list[str] | None, kwargs: dict[str, str] | None) str

Get the shell command from code/args/kwargs.

gptme.tools.shell.get_workspace_cwd() str | None

Get the workspace directory for the current context, if set.

gptme.tools.shell.preview_shell(cmd: str, _: Path | None) str

Prepare preview for shell command.

gptme.tools.shell.set_shell(shell: ShellSession) None

Set the shell session for the current context (for testing).

gptme.tools.shell.set_workspace_cwd(cwd: str) None

Set the workspace directory for the current context (thread-safe).

Call this before any shell creation to ensure the shell subprocess starts in the correct directory, even with concurrent sessions. This is the thread-safe replacement for os.chdir() in server contexts.

gptme.tools.shell.split_commands(script: str) list[str]

Split at top-level newlines, preserving Bash lists and original source.

Tree-sitter spans include heredoc bodies and use byte offsets, so slicing UTF-8 source preserves quoted delimiters and non-ASCII text without rewrites. Keep bashlex as a compatibility fallback for one release: tree-sitter’s error recovery must never turn an incomplete tree into executable fragments.

gptme.tools.shell.strip_ansi_codes(text: str) str

Strip ANSI escape sequences from text.

gptme.tools.shell.trim_blank_lines(text: str) str

Trim only leading and trailing blank (whitespace-only) lines.

Interior blank lines are kept. Unlike str.strip(), the first/last contentful lines are returned verbatim, so indentation (e.g. from sed/head/tail of indented code) is preserved.