plugins/plugin-shell/README.md
A comprehensive shell command execution plugin for ElizaOS with PTY support, background execution, session management, and security restrictions.
Key Features:
Available in three languages:
Just want your agent to execute commands? Here's the fastest path:
Install the plugin:
cd your-eliza-project
bun add @elizaos/plugin-shell
Create/update your .env:
SHELL_ALLOWED_DIRECTORY=/path/to/safe/directory
Add to your character:
const character = {
// ... other config
plugins: ["@elizaos/plugin-shell"],
};
Run: bun start
โ ๏ธ Security note: The agent can ONLY execute commands within SHELL_ALLOWED_DIRECTORY - choose wisely!
@lydell/node-ptyplugin-shell/
โโโ typescript/ # TypeScript implementation
โ โโโ providers/ # SHELL_HISTORY provider
โ โโโ services/ # ShellService
โ โโโ utils/ # Path validation, security checks
โ โโโ types/ # Type definitions
โ โโโ __tests__/ # Unit tests
โโโ python/ # Python implementation
โ โโโ elizaos_plugin_shell/
โ โ โโโ service.py # ShellService
โ โ โโโ path_utils.py
โ โ โโโ types.py
โ โโโ tests/ # Python tests
โโโ rust/ # Rust implementation
โ โโโ src/
โ โ โโโ lib.rs
โ โ โโโ service.rs # ShellService
โ โ โโโ path_utils.rs
โ โ โโโ types.rs
โ โโโ tests/ # Integration tests
โโโ package.json # NPM package config
# Using bun (recommended)
bun add @elizaos/plugin-shell
# Using npm
npm install @elizaos/plugin-shell
Set the following environment variables:
# Set the allowed directory (commands can only run here)
SHELL_ALLOWED_DIRECTORY=/home/user/safe-workspace
# OPTIONAL: Set custom timeout in milliseconds (default: 30000)
SHELL_TIMEOUT=60000
# OPTIONAL: Add additional forbidden commands (comma-separated)
SHELL_FORBIDDEN_COMMANDS=rm,mv,cp,chmod,chown,shutdown,reboot
# OPTIONAL: Maximum output characters to capture (default: 200000)
SHELL_MAX_OUTPUT_CHARS=200000
# OPTIONAL: Milliseconds before backgrounding (default: 10000)
SHELL_BACKGROUND_MS=10000
# OPTIONAL: Allow background execution (default: true)
SHELL_ALLOW_BACKGROUND=true
# OPTIONAL: Session record TTL in milliseconds (default: 1800000 = 30min)
SHELL_JOB_TTL_MS=1800000
import { shellPlugin, ShellService } from "@elizaos/plugin-shell";
// Use as a plugin
const character = {
plugins: [shellPlugin],
};
// Or use the service directly
const service = new ShellService(runtime);
const result = await service.executeCommand("ls -la", "conversation-123");
// Advanced: Use exec with PTY and background support
const execResult = await service.exec("npm install", {
pty: true, // Run with pseudo-terminal
background: false, // Or yieldMs: 5000 to auto-background after 5s
timeout: 300, // 5 minute timeout
workdir: "/project",
});
if (execResult.status === "running") {
console.log(`Background session: ${execResult.sessionId}`);
// Poll for updates
const pollResult = await service.processAction({
action: "poll",
sessionId: execResult.sessionId,
});
console.log(pollResult.message);
}
// Get the service from an Eliza agent runtime
const shellService = runtime.getService<ShellService>("shell");
Shell execution is exposed through the canonical SHELL action in
@elizaos/plugin-coding-tools. This plugin supplies the shell service,
approval service, and history provider.
Executes ANY shell command within the allowed directory, including file operations.
Examples:
run ls -la - List files with detailsexecute npm test - Run testscreate a file called hello.txt - Creates a new filecheck git status - Show git repository statusManage running and finished shell sessions. Supports the following operations:
| Action | Description |
|---|---|
list | List all running and finished sessions |
poll | Get new output from a running session |
log | Get session output with offset/limit |
write | Write data to session stdin |
send-keys | Send terminal key sequences (arrows, ctrl, etc) |
submit | Send carriage return (Enter) |
paste | Paste text with bracketed paste mode |
kill | Kill a running session |
clear | Clear a finished session record |
remove | Kill (if running) and remove session |
Examples:
list all running processescheck session calm-harborkill the process swift-reefsend enter to session brisk-coveExamples:
SHELL action=clear_historySHELL action=view_historyThe plugin includes a SHELL_HISTORY provider that makes the following information available to the agent:
All commands execute within SHELL_ALLOWED_DIRECTORY:
cd .. stops at the allowed directory rootBy default, these potentially dangerous commands are blocked:
rm -rf /, rmdirchmod 777, chown, chgrpshutdown, reboot, halt, poweroffkill -9, killall, pkillsudo rm -rf, su, passwd, useradd, userdelformat, fdisk, mkfs, dd if=/dev/zero, shred../ and similar patternscd typescript
bun run build.ts # Build
npx vitest # Run tests
# From plugin root
bun run build # Build TypeScript
bun run build:python # Build Python
bun run build:rust # Build Rust
bun run test # Test TypeScript
bun run test:python # Test Python
bun run test:rust # Test Rust
| Field | Type | Description |
|---|---|---|
success | boolean | Whether the command executed successfully |
stdout | string | Standard output from the command |
stderr | string | Standard error output |
exitCode | number | null | Exit code of the command |
error | string | undefined | Error message if command failed |
executedIn | string | Directory where command was executed |
| Field | Type | Description |
|---|---|---|
type | FileOperationType | Type of operation (create, write, read, delete, mkdir, move, copy) |
target | string | Target file/directory path |
secondaryTarget | string | undefined | Secondary target for move/copy |
| Field | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Whether shell is enabled |
allowedDirectory | string | cwd | Directory to restrict commands to |
timeout | number | 30000 | Timeout in milliseconds |
forbiddenCommands | string[] | [...] | List of forbidden commands |
maxOutputChars | number | 200000 | Max output characters to capture |
pendingMaxOutputChars | number | 200000 | Max pending output per stream |
defaultBackgroundMs | number | 10000 | Default background yield window |
allowBackground | boolean | true | Allow background execution |
| Field | Type | Description |
|---|---|---|
id | string | Unique session identifier (slug) |
command | string | The executed command |
pid | number | undefined | Process ID |
startedAt | number | Start timestamp |
cwd | string | undefined | Working directory |
aggregated | string | Accumulated output |
tail | string | Last 2000 chars of output |
exited | boolean | Whether process has exited |
exitCode | number | null | Exit code (if exited) |
exitSignal | string | number | null | Exit signal (if killed) |
truncated | boolean | Whether output was truncated |
backgrounded | boolean | Whether running in background |
type ExecResult =
| { status: "running"; sessionId: string; pid?: number; startedAt: number; cwd?: string; tail?: string }
| { status: "completed" | "failed"; exitCode: number | null; durationMs: number; aggregated: string; cwd?: string; timedOut?: boolean; reason?: string }
| Field | Type | Description |
|---|---|---|
workdir | string | Working directory |
env | Record<string, string> | Additional environment variables |
yieldMs | number | Yield to background after this time |
background | boolean | Run immediately in background |
timeout | number | Timeout in seconds |
pty | boolean | Use pseudo-terminal |
conversationId | string | Conversation ID for history tracking |
scopeKey | string | Scope key for session isolation |
sessionKey | string | Session key for notifications |
notifyOnExit | boolean | Notify on background exit |
onUpdate | (session) => void | Callback for output updates |
Contributions are welcome! Please ensure:
MIT - See LICENSE for details.