@elizaos/plugin-shell
Shell command execution plugin for elizaOS. Adds sandboxed shell access, PTY support, background session management, command approval, and shell history to an Eliza agent.
What it does
- Executes shell commands restricted to a configured directory (
SHELL_ALLOWED_DIRECTORY). - Supports interactive terminal applications via PTY (
@lydell/node-pty, optional). - Runs long commands in the background with named sessions; poll, send-keys, paste, and kill them later.
- Maintains per-conversation command history with stdout/stderr/exit-code capture.
- Provides the
SHELL_HISTORYcontext provider so the agent always knows its cwd and recent commands. - Provides
ExecApprovalServiceto gate commands through an allowlist and user-approval flow.
The agent-facing SHELL action that exposes shell execution is in @elizaos/plugin-coding-tools, which consumes this plugin's services. Its action parameter (list/poll/kill/etc.) drives ShellService.processAction().
Installation
bun add @elizaos/plugin-shell
Configuration
# Required — commands cannot execute outside this directory
SHELL_ALLOWED_DIRECTORY=/path/to/safe/workspace
# Optional
SHELL_TIMEOUT=30000 # per-command timeout ms (simple executeCommand)
SHELL_FORBIDDEN_COMMANDS=rm,mv # comma-separated additions to the default blocklist
SHELL_MAX_OUTPUT_CHARS=200000 # max captured output chars per session
SHELL_BACKGROUND_MS=10000 # yield window before auto-backgrounding (ms)
SHELL_ALLOW_BACKGROUND=true # set "false" to disable background execution
SHELL_JOB_TTL_MS=1800000 # finished session record TTL (ms)
SHELL_ALLOWED_DIRECTORY must point to an existing directory. The service throws at start if it is missing.
Enabling
Auto-enabled when config.features.shell is truthy. Not available on iOS, ELIZA_BUILD_VARIANT=store builds, or Android unless ELIZA_RUNTIME_MODE=local-yolo.
To enable explicitly in a character file:
import shellPlugin from "@elizaos/plugin-shell";
const character = {
plugins: [shellPlugin],
};
Security
- All commands execute within
SHELL_ALLOWED_DIRECTORY. Path traversal and absolute paths outside the boundary are rejected. - A built-in blocklist prevents the most destructive commands (see
DEFAULT_FORBIDDEN_COMMANDSinutils/config.ts). - Additional forbidden commands can be added via
SHELL_FORBIDDEN_COMMANDS. - Commands time out automatically. Output is capped at
SHELL_MAX_OUTPUT_CHARS. ExecApprovalServicecan gate commands through an allowlist + user approval before execution.- Local execution is disabled in cloud mode (
isCloudExecutionMode).
Process actions
Background sessions support these operations via ShellService.processAction():
| Action | Description |
|---|---|
list |
List all running and finished sessions |
poll |
Drain new output from a running session |
log |
Read session output with offset/limit pagination |
write |
Write raw data to session stdin |
send-keys |
Send terminal key sequences (arrows, ctrl+c, etc.) |
submit |
Send carriage return (Enter) |
paste |
Paste text with bracketed paste mode |
kill |
Kill a running session |
clear |
Remove a finished session record |
remove |
Kill (if running) and remove a session |
Usage from code
import { ShellService } from "@elizaos/plugin-shell";
// Simple synchronous execution
const shellService = runtime.getService<ShellService>("shell");
const result = await shellService.executeCommand("ls -la", conversationId);
// Advanced: PTY + background
const execResult = await shellService.exec("bun install", {
pty: true,
yieldMs: 5000, // background after 5 s if still running
timeout: 300, // 5-minute hard timeout (seconds)
workdir: "/project",
});
if (execResult.status === "running") {
// Poll later
const poll = await shellService.processAction({
action: "poll",
sessionId: execResult.sessionId,
});
}
Development
bun run --cwd plugins/plugin-shell build # build dist/
bun run --cwd plugins/plugin-shell test # vitest
bun run --cwd plugins/plugin-shell dev # hot-reload build