Files
wehub-resource-sync 426e9eeabd
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Waiting to run
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Waiting to run
Build Agent Image / build-and-push (push) Waiting to run
Chat shell gestures / Chat shell gesture + parity e2e (push) Waiting to run
Cloud Gateway Discord / Test (push) Waiting to run
Cloud Gateway Webhook / Test (push) Waiting to run
Cloud Tests / lint-and-types (push) Waiting to run
Cloud Tests / unit-tests (push) Waiting to run
Cloud Tests / integration-tests (push) Waiting to run
Cloud Tests / e2e-tests (push) Blocked by required conditions
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Deploy Apps Worker (Product 2) / Determine environment (push) Waiting to run
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Blocked by required conditions
Deploy Eliza Provisioning Worker / Determine environment (push) Waiting to run
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Blocked by required conditions
Dev Smoke / Classify changed paths (push) Waiting to run
Dev Smoke / bun run dev onboarding chat (push) Blocked by required conditions
Dev Smoke / Vite HMR dependency-level smoke (push) Blocked by required conditions
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Waiting to run
Publish @elizaos/example-code / check_npm (push) Waiting to run
Publish @elizaos/example-code / publish_npm (push) Blocked by required conditions
Publish @elizaos/plugin-elizacloud / verify_version (push) Waiting to run
Publish @elizaos/plugin-elizacloud / publish_npm (push) Blocked by required conditions
Sandbox Live Smoke / Sandbox live smoke (push) Waiting to run
Snap Build & Test / Build Snap (amd64) (push) Waiting to run
Snap Build & Test / Build Snap (arm64) (push) Waiting to run
supply-chain / sbom (push) Waiting to run
supply-chain / vulnerability-scan (push) Waiting to run
Build, Push & Deploy to Phala Cloud / build-and-push (push) Waiting to run
Test Packaging / Validate Packaging Configs (push) Waiting to run
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Waiting to run
Test Packaging / Pack & Test JS Tarballs (push) Waiting to run
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Waiting to run
UI Fixture E2E / ui-fixture-e2e (push) Waiting to run
UI Fixture E2E / fixture-e2e (push) Waiting to run
UI Story Gate / story-gate (push) Waiting to run
vault-ci / test (macos-latest) (push) Waiting to run
vault-ci / test (ubuntu-latest) (push) Waiting to run
vault-ci / test (windows-latest) (push) Waiting to run
vault-ci / app-core wiring tests (push) Waiting to run
verify-patches / verify patches/CHECKSUMS.sha256 (push) Waiting to run
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Waiting to run
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Waiting to run
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Waiting to run
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Waiting to run
Voice Benchmark Smoke / voice bench smoke summary (push) Blocked by required conditions
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Waiting to run
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Waiting to run
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Waiting to run
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Waiting to run
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Waiting to run
Test Packaging / Build & Test PyPI Package (push) Waiting to run
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00

11 KiB

@elizaos/plugin-shell

Shell command execution, PTY support, background session management, and command approval for Eliza agents.

Purpose / role

Adds shell-execution capability to an Eliza agent: run system commands within a sandboxed directory, track running processes as named sessions, and stream output. Loaded as @elizaos/plugin-shell. Auto-enabled when config.features.shell is truthy and the runtime platform supports a terminal (disabled for iOS, store builds; Android requires local-yolo mode). See auto-enable.ts and index.ts → autoEnable.shouldEnable.

Plugin surface

Services (registered in Plugin.services):

  • ShellService (serviceType = "shell") — core executor. Run commands via executeCommand() (simple) or exec() (PTY, background, yield, session tracking). Manage sessions via processAction(). Retrieve via runtime.getService<ShellService>("shell").
  • ExecApprovalService (serviceType = "exec_approval") — command approval gating. Maintains an allowlist file; routes unapproved commands through the elizaOS ApprovalService UI. Retrieve via runtime.getService<ExecApprovalService>("exec_approval").

Providers (registered in Plugin.providers):

  • shellHistoryProvider (name = "SHELL_HISTORY", position = 99) — injects the last 10 commands (with stdout/stderr/exit code), current working directory, allowed directory, and recent file operations into context. Only fires in terminal or code contexts.

Actions: none — this plugin registers no actions. The agent-facing SHELL action lives in @elizaos/plugin-coding-tools (src/actions/bash.ts), which consumes ShellService; its action parameter (e.g. list, poll, kill) maps to ShellService.processAction() for process management.

Evaluators / Routes / Events: none.

Layout

plugins/plugin-shell/
├── index.ts                    # Plugin object export; auto-enable logic
├── auto-enable.ts              # Lightweight shouldEnable() for the auto-enable engine
├── types/
│   └── index.ts                # All shared types: ShellConfig, ProcessSession,
│                               #   FinishedSession, ExecResult, ExecuteOptions, etc.
├── services/
│   ├── shellService.ts         # ShellService — executeCommand(), exec(), processAction()
│   └── processRegistry.ts     # Module-level process registry (running/finished sessions)
├── providers/
│   └── shellHistoryProvider.ts # SHELL_HISTORY provider
├── approvals/
│   ├── service.ts              # ExecApprovalService
│   ├── allowlist.ts            # File-backed allowlist CRUD
│   ├── analysis.ts             # Command risk analysis, evaluateShellAllowlist()
│   ├── types.ts                # Approval types and DEFAULT_SAFE_BINS
│   └── index.ts                # Barrel export for the approvals module
├── utils/
│   ├── config.ts               # loadShellConfig() — env → ShellConfig; DEFAULT_FORBIDDEN_COMMANDS
│   ├── pathUtils.ts            # validatePath() — enforces allowedDirectory boundary
│   ├── shellUtils.ts           # getShellConfig(), spawnWithFallback(), killSession(),
│   │                           #   sanitizeBinaryOutput(), sliceLogLines(), etc.
│   ├── terminalCapabilities.ts # detectTerminalSupport(), resolveTerminalShell(),
│   │                           #   missingTerminalToolForCommand()
│   ├── ptyKeys.ts              # encodeKeySequence(), encodePaste(), stripDsrRequests()
│   ├── shellArgv.ts            # Shell argument parsing helpers
│   └── processQueue.ts         # Async process queue utility
└── prompts.ts                  # commandExtractionTemplate — LLM prompt to extract a shell command from a request

Commands

Scripts are defined in package.json; run them from the repo root with bun run --cwd:

bun run --cwd plugins/plugin-shell clean         # remove build output
bun run --cwd plugins/plugin-shell build         # build package artifacts
bun run --cwd plugins/plugin-shell build:ts      # ts build lane
bun run --cwd plugins/plugin-shell dev           # development build/watch lane
bun run --cwd plugins/plugin-shell typecheck     # TypeScript typecheck
bun run --cwd plugins/plugin-shell lint          # mutating Biome check
bun run --cwd plugins/plugin-shell lint:check    # read-only Biome check
bun run --cwd plugins/plugin-shell format        # write formatting
bun run --cwd plugins/plugin-shell format:check  # read-only formatting check
bun run --cwd plugins/plugin-shell test          # run package tests

Config / env vars

Variable Required Default Description
SHELL_ALLOWED_DIRECTORY yes process.cwd() All commands restricted to this directory. Must exist.
SHELL_TIMEOUT no 30000 Per-command timeout (ms) for executeCommand().
SHELL_FORBIDDEN_COMMANDS no Comma-separated additional forbidden commands (merged with DEFAULT_FORBIDDEN_COMMANDS).
SHELL_MAX_OUTPUT_CHARS no 200000 Max aggregated output chars captured per session.
SHELL_PENDING_MAX_OUTPUT_CHARS no 200000 Max pending output buffered per stream.
SHELL_BACKGROUND_MS no 10000 Default yield window before auto-backgrounding in exec().
SHELL_ALLOW_BACKGROUND no true Set to "false" to disable background/yield execution.
SHELL_JOB_TTL_MS no 1800000 TTL for finished session records (ms).

Config is validated by zod in utils/config.ts → loadShellConfig(). Missing or non-existent SHELL_ALLOWED_DIRECTORY throws at service start.

How to extend

Add a new process action — extend the ProcessAction union in types/index.ts, then add the corresponding case in ShellService.processAction() in services/shellService.ts.

Add a new util — place it in utils/. Export from utils/index.ts and re-export from the top-level index.ts if it needs to be part of the public package API.

Add a new approval rule — extend approvals/types.ts and approvals/analysis.ts → analyzeShellCommand().

Expose a new provider — create the provider file in providers/, register it in the Plugin.providers array in index.ts, and add a provider spec in generated/specs/ (see shellHistoryProvider.ts → requireProviderSpec).

Conventions / gotchas

  • @lydell/node-pty is optional — PTY spawn is wrapped in a dynamic import() with a fallback to plain cross-spawn. On platforms where native modules are absent, pty: true degrades to non-PTY with a warning. Do not add node-pty to dependencies; keep it in optionalDependencies.
  • Cloud modeShellService.exec() and executeCommand() short-circuit when isCloudExecutionMode(runtime) is true. Local shell execution is explicitly disabled in cloud mode.
  • Sandbox mode — when shouldUseSandboxExecution(runtime) is true, commands route through SandboxManager.exec() instead of spawning directly. Background/PTY options are silently ignored in sandbox mode.
  • Platform gating — iOS and ELIZA_BUILD_VARIANT=store builds never enable this plugin. Android requires ELIZA_RUNTIME_MODE=local-yolo. Check auto-enable.ts → terminalSupportedByEnv.
  • processRegistry is module-levelservices/processRegistry.ts holds process state in module-scope Maps. In tests, call resetProcessRegistryForTests() between cases.
  • No actions here — the agent-facing SHELL action is owned by @elizaos/plugin-coding-tools. This plugin only provides the service, approval service, and history provider.
  • SHELL_ALLOWED_DIRECTORY must existloadShellConfig() calls fs.statSync() and throws ENOENT if the path does not exist. Set it before the agent starts.

NON-NEGOTIABLE — evidence, trajectories & real end-to-end tests

The binding, repo-wide standard is AGENTS.md. Read it. Nothing in this package is done until it is proven done — a reviewer must confirm it works without reading the code, from the artifacts you attach. This applies to every feature, fix, refactor, and chore here. "Tests pass" is not proof; "CI is green" is not proof.

  • Record AND read model trajectories. Capture the actual inputs and outputs of the model from a live LLM — not the deterministic proxy, not a mock: the prompt, the providers/context, the raw model output, every tool/action call, and the result. Then open the trajectory and review it by hand. A captured-but-unread trajectory is not evidence (packages/scenario-runner/bin/eliza-scenarios run <scenario> --report <out>).
  • Real, full-featured E2E — no larp. Every feature ships detailed end-to-end tests that drive the real path end to end. Not the happy "front door" only: cover error paths, edge/empty/invalid input, concurrency, roles/permissions, and adversarial input. A test that asserts against a mock/stub/fixture standing in for the thing under test does not count. If the real model/device/chain/connector/account is hard to reach, make it reachable — that is the work, not an excuse to mock. If the existing tests here are shallow or mocked, fixing them is part of your change.
  • Screenshots + logs at every phase, plus a complete walkthrough video/run-through of the entire feature or view, start to finish (bun run test:e2e:record).
  • Manually review every artifact the change touches — never just the green check: client logs (console + network), server logs ([ClassName] …), the model trajectories in and out, before/after full-page screenshots, and the domain artifacts listed below for this package.
  • No residuals. No shortcuts. The goal is not "done" — it is everything done. Clear every blocker by the hard path: build the real architecture, stand up the real model/device/service, actually test it. Never leave a TODO, a stub, a stepping-stone, or a "follow-up." When unsure, research thoroughly, weigh the options, and ship the best, highest-effort, production-ready version. Keep going until every possibility is exhausted.

Artifacts → attached inline in the PR (MP4 video, JPG screenshots, logs in <details>); attach each evidence type or explicitly mark it N/A with a reason — never leave it blank. If develop moved and changed behavior, re-capture evidence; stale proof is worse than none.

Capture & manually review for this package — CLI / tooling:

  • The real command/flow invocation transcript (args in, stdout/stderr, exit code) and the artifacts it generated (files, scaffolds, manifests, screenshots/recordings).
  • Failure paths: bad args, missing deps, partial state, permission/network errors.
  • A recording/log of the actual run end to end — not a unit test of one helper.
  • Any model interaction captured as a live trajectory and reviewed.