Repository: https://github.com/strands-agents/shell Stars: 103 | Forks: 12 | Language: Rust License: Apache-2.0 | Last Updated: 2026-06-17 Homepage: https://strandsagents.com Tags: Shell, Rust, Sandboxing


1. 專案概覽 (Project Overview)

1.1 這是什麼

Strands Shell 是一個完全在 userspace (使用者空間) 中執行的 Bourne-compatible shell (Bourne 相容 shell),專為 AI agent (AI 代理人) 設計。它的核心理念是:給 agent 一個 shell,但不給它你機器的鑰匙

在 AI agent 開發中,agent 經常需要執行 shell 指令來完成任務:安裝相依套件、執行測試、搜尋錯誤訊息、迭代修正。這些操作需要速度隔離性,但傳統方案(Docker container、雲端 sandbox)都有各自的代價——冷啟動延遲、網路依賴、複雜的設定流程。

Strands Shell 的做法截然不同:它在同一個 process (程序) 內實作了一整套虛擬作業系統環境,包含 VFS (Virtual File System; 虛擬檔案系統)、網路控制、憑證注入,以及 50+ 個常用指令(grepsedjqcurlfind 等),完全不需要 forkexec 或任何 system call (系統呼叫)。

1.2 誰開發的

Strands Shell 是 AWS 開源的 Strands Agents 生態系的一部分。Strands Agents 是一個完整的 AI agent 開發平台,由 13 個 repository 組成,涵蓋 SDK、工具集、評估框架、文件等各個層面。Shell 是這個生態系中負責「安全 shell 執行環境」的核心元件。

1.3 為什麼重要

特性Docker雲端 SandboxStrands Shell
冷啟動~200ms~1s (網路)<1ms
隔離方式Container namespaceMicroVMIn-process VFS
網路控制iptables / sidecar平台政策URL allowlist + SSRF guard
機密管理Env vars (agent 可讀)平台特定Per-request inject,agent 不可見
安裝方式Docker daemonAPI key + 網路pip install strands-shell
支援平台Linux僅雲端macOS, Linux, WASM

最值得注意的三個設計亮點:

  1. <1ms 冷啟動:沒有 container、沒有 VM,就是記憶體內的資料結構。每個 request 建立一個新的 Shell instance 是預期的使用模式。
  2. Credential injection (憑證注入):agent 永遠看不到 API key 的值。Kernel 在每次 HTTP request 時自動注入憑證,即使 redirect (重新導向) 也不會重新注入,防止 credential leakage (憑證外洩)。
  3. Default-deny (預設拒絕):出廠狀態是一個完全空的 sandbox。沒有檔案、沒有網路、沒有憑證。你必須明確 allowlist (允許清單) agent 能存取的每一項資源。

1.4 技術棧

  • 核心語言:Rust
  • Python binding:PyO3 + maturin
  • Node.js binding:napi-rs
  • WASM 支援:wasm32-wasip2
  • MCP 支援:內建 MCP server(JSON-RPC over stdio)
  • Scripting:內嵌 Lua 5.4

2. 核心架構 (Core Architecture)

2.1 分層架構

Strands Shell 的架構分為六個清晰的層次,每一層都有明確的職責邊界:

層級模組職責
Public APIShell, ShellBuilder, OutputBuilder-based 進入點
Kernelos::Kernel抽象所有 OS 操作的 trait
VFS Kernelvfs_kernel預設 kernel,由 in-memory VFS 支撐
VFSvfsIn-memory 檔案系統(含 host bind mount)
ExecutorexecShell 直譯器(parsing、expansion、pipeline)
Commandscommands, builtins內建指令實作

flowchart TB
    subgraph "使用者程式碼"
        agent["AI Agent
(Strands SDK / LangGraph / 任何框架)"] end agent -->|"MCP / Python / Node.js / Rust"| shell_api subgraph "Strands Shell" shell_api["Shell Public API
ShellBuilder → Shell → Output"] subgraph "Kernel 安全邊界" kernel_trait["os::Kernel Trait
(所有 I/O 必經此 trait)"] vfs_kernel["VfsKernel
(預設 Kernel 實作)"] subgraph "受控資源" vfs["VFS
In-memory 檔案系統"] net["Network
SSRF Guard + URL Allowlist"] creds["Credentials
Per-URL 自動注入"] limits["Limits
Timeout / Output / FDs / Inodes"] end end subgraph "執行引擎" parser["Parser
Bourne Shell 語法解析"] executor["Executor
Pipeline / Redirect / Expansion"] end subgraph "指令集" builtins["25 Builtins
cd, export, alias, set, ..."] commands["33 Commands
grep, sed, curl, jq, find, ..."] lua["Lua 5.4 Runtime
進階 scripting"] end shell_api --> kernel_trait kernel_trait --> vfs_kernel vfs_kernel --> vfs vfs_kernel --> net vfs_kernel --> creds vfs_kernel --> limits shell_api --> parser parser --> executor executor --> builtins executor --> commands executor --> lua commands -->|"所有 I/O"| kernel_trait end style kernel_trait fill:#ff6b6b,color:#fff style vfs fill:#4ecdc4,color:#fff style net fill:#4ecdc4,color:#fff style creds fill:#4ecdc4,color:#fff style limits fill:#4ecdc4,color:#fff

2.2 Kernel Trait — 安全邊界的核心

整個安全模型的關鍵在於 os::Kernel trait。所有檔案系統操作、網路存取、程序管理都必須經過這個 trait,沒有任何指令可以繞過它直接呼叫 system call。


sequenceDiagram
    participant Agent as AI Agent
    participant Shell as Shell.run()
    participant Exec as Executor
    participant Cmd as grep / curl / cat
    participant Kernel as Kernel Trait
    participant VFS as VFS / Network

    Agent->>Shell: shell.run("grep -rn TODO /workspace")
    Shell->>Exec: parse + execute
    Exec->>Cmd: dispatch "grep"
    Cmd->>Kernel: open("/workspace", READ)
    Kernel->>Kernel: 檢查 bind mount 是否存在
    Kernel->>Kernel: 檢查 permission
    Kernel->>VFS: 讀取 VFS inode
    VFS-->>Kernel: 檔案內容
    Kernel-->>Cmd: fd (file descriptor)
    Cmd->>Kernel: readdir, stat, ...
    Cmd-->>Exec: stdout output
    Exec-->>Shell: Output{status, stdout, stderr}
    Shell-->>Agent: 回傳結果

    Note over Kernel: 每一步 I/O 都經過 Kernel
    Note over Kernel: 沒有 bind 的路徑 → 不存在
    Note over Kernel: 沒有 allowlist 的 URL → 被阻擋

2.3 VFS (Virtual File System) 設計

VFS 是一個完全在記憶體中的檔案系統,使用 inode (索引節點) 架構:

  • InodeData::File(Vec<u8>):常規檔案,資料存在記憶體中
  • InodeData::Dir(HashMap<String, Ino>):目錄,子項目的名稱到 inode 的映射
  • InodeData::Symlink(String):符號連結
  • InodeData::HostFile(String, bool):Bind mount 到 host 的檔案(host_path, readonly)
  • InodeData::HostDir(String, bool):Bind mount 到 host 的目錄(host_path, readonly)
  • InodeData::FifoCharDeviceBlockDevice:特殊裝置節點

Bind mount 支援兩種模式:

模式說明使用時機
copy建構時把 host 目錄快照 (snapshot) 到 VFS 記憶體原始碼、設定檔(agent 的修改不影響 host)
direct直接穿透到 host 檔案系統輸出目錄(agent 需要寫入真實檔案)

Symlink traversal escape (符號連結穿越逃脫) 防護VfsKernel::resolve_host() 會 canonicalize (正規化) 路徑,並驗證解析後的路徑仍在 bind mount base 之內。如果 symlink 指向 mount 外的位置,存取會被拒絕。開啟檔案後還會透過 /proc/self/fd/ 再次驗證,消除 TOCTOU (Time-of-Check-to-Time-of-Use) race condition。

2.4 指令系統

指令分為兩大類:

Builtins (內建指令):會修改 shell 狀態的指令,定義在 src/builtins/ 下。包括:cdexportaliassetshiftlocalreadechoprintftesttrapumaskunsetwaitxargsfindgetoptshashtypeluapwd 等 25 個。

Isolated Commands (隔離指令):不修改 shell 狀態,定義在 src/commands/ 下。每個指令使用 #[command("name")] proc-macro 註冊。包括:grepsedcatheadtailjqcurlcpmvrmmkdirlssortcuttruniqwcteetouchchmodlnbasenamedirnamereadlinkmktemprmdirsleepdateenvtruefalseechopwd 等 33 個。


3. 安裝與設定 (Installation & Setup)

3.1 系統需求

  • Python: 3.10+
  • Node.js: 18+
  • Rust (僅開發用): stable toolchain
  • 作業系統: macOS, Linux(WASM target 亦可)

3.2 Python 安裝

1# 使用 pip(推薦用 uv 管理虛擬環境)
2pip install strands-shell
3
4# 或使用 uv
5uv pip install strands-shell

驗證安裝:

1import strands_shell
2shell = strands_shell.Shell()
3out = shell.run("echo 'Hello from Strands Shell!'")
4print(out.stdout)  # Hello from Strands Shell!
5print(out.status)  # 0

3.3 Node.js 安裝

1npm install @strands-agents/shell

驗證安裝:

1import { Shell } from '@strands-agents/shell'
2
3const shell = await Shell.create()
4const out = await shell.run('echo "Hello from Strands Shell!"')
5console.log(out.stdout) // Hello from Strands Shell!

3.4 MCP Server 設定

Strands Shell 內建 MCP server,可以與任何支援 MCP protocol 的 AI 工具整合。將以下設定加入你的 MCP client 設定檔:

1{
2  "mcpServers": {
3    "shell": {
4      "command": "uvx",
5      "args": ["strands-shell", "--mcp"]
6    }
7  }
8}

使用 TOML 設定檔啟動:

1uvx strands-shell --config sandbox.toml --mcp

MCP server 提供四個 tool:

  • shell:執行 shell 指令,回傳 stdout + stderr + exit_code
  • read_file:讀取 VFS 中的檔案(支援文字、圖片、二進位)
  • write_file:寫入檔案到 VFS
  • list_dir:列出 VFS 目錄內容

3.5 從原始碼建置(開發者)

 1# Clone
 2git clone https://github.com/strands-agents/shell.git
 3cd shell
 4
 5# Rust 核心
 6cargo build
 7cargo test --workspace --all-targets
 8
 9# Python bindings
10python -m venv .venv && source .venv/bin/activate
11pip install maturin pytest
12maturin develop --features python
13pytest tests/python -v
14
15# Node.js bindings
16npm install
17npm run build
18npm test

4. 使用方式與程式碼範例 (Usage & Code Examples)

4.1 基本使用:建立隔離的工作環境

 1import strands_shell
 2
 3# 建立一個帶有 bind mount 的 shell
 4shell = strands_shell.Shell(
 5    binds=[
 6        # copy 模式:把 host 的 /my/project 快照到 VFS 的 /workspace
 7        # agent 的任何修改不會影響 host 上的原始檔案
 8        strands_shell.Bind(
 9            source="/my/project",        # host 上的路徑
10            destination="/workspace",    # VFS 中的路徑
11            mode="copy"                  # 快照模式(預設是 direct)
12        ),
13        # direct 模式:agent 的寫入會直接反映到 host
14        # 適用於輸出目錄
15        strands_shell.Bind(
16            source="/tmp/output",
17            destination="/output",
18            mode="direct"
19        ),
20    ],
21    env={"PROJECT": "demo", "LANG": "en_US.UTF-8"},  # 設定環境變數
22    timeout=30.0,  # 每個指令的超時限制(秒)
23)
24
25# 執行指令——狀態在多次 run() 之間保持
26shell.run("cd /workspace")
27shell.run("X=42")
28out = shell.run("echo $X from $PWD")
29print(out.stdout.strip())  # 42 from /workspace
30
31# 搜尋 TODO 標記
32out = shell.run("grep -rn TODO /workspace")
33print(out.stdout)
34
35# 使用 pipe(管線)
36out = shell.run("find /workspace -name '*.py' | head -10")
37print(out.stdout)

逐行解說

  • strands_shell.Bind(mode="copy"):快照模式讓 agent 在隔離環境中操作,不會意外修改你的專案檔案
  • strands_shell.Bind(mode="direct"):直通模式讓 agent 能把結果寫回 host 檔案系統
  • shell.run("cd /workspace"):狀態持久化——cwd、環境變數、shell function 都會在 run() 之間保留
  • shell.run("grep -rn TODO /workspace"):使用 Strands Shell 內建的 grep 實作,不是 host 的 grep

4.2 安全的 HTTP 存取與憑證注入

 1import strands_shell
 2
 3shell = strands_shell.Shell(
 4    credentials=[
 5        # 從環境變數注入 Bearer token
 6        # agent 永遠看不到 token 的值——Kernel 在 HTTP request 時自動注入
 7        strands_shell.Cred(
 8            url="https://api.github.com/",
 9            env_var="GITHUB_TOKEN"  # 從 host 的環境變數讀取
10        ),
11        # 直接提供 token 值(適用於測試)
12        strands_shell.Cred(
13            url="https://api.example.com/",
14            token="sk-test-12345"
15        ),
16    ],
17    # 只允許存取這些 URL prefix
18    # 未列入的 URL 會被 SSRF guard 阻擋
19    allowed_urls=[
20        "https://api.github.com/",
21        "https://api.example.com/",
22    ],
23)
24
25# curl 會自動帶上 Bearer token——agent 不需要知道 token 是什麼
26out = shell.run('curl -s https://api.github.com/user')
27print(out.stdout)  # GitHub API 回傳的使用者資訊
28
29# 嘗試存取未授權的 URL → 被阻擋
30out = shell.run('curl https://evil.com/steal-data')
31print(out.status)   # 非 0 的 exit code
32print(out.stderr)   # 錯誤訊息

安全機制解說

  • Credential injection (憑證注入)Cred(env_var="GITHUB_TOKEN") 表示 Kernel 會在 runtime 從 $GITHUB_TOKEN 讀取值,在每次 matching URL 的 HTTP request 中自動注入 Authorization: Bearer <token> header。Agent 的 shell 環境中看不到這個環境變數。
  • URL allowlist:只有 allowed_urls 中列出的 prefix 才能被存取。Private IP ranges (RFC1918, link-local, loopback, IMDS 169.254.169.254) 預設被 SSRF guard 阻擋。
  • Redirect 安全:即使 server 把 agent redirect 回同一個 host,Kernel 也不會重新注入 credential,防止 credential 被 redirect 到惡意 endpoint。

4.3 使用 TOML 設定檔管理複雜配置

 1# sandbox.toml — 一個完整的設定範例
 2
 3# 掛載工作目錄(copy 模式,隔離)
 4[[bind]]
 5mode = "copy"
 6source = "/home/user/project"
 7destination = "/workspace"
 8
 9# 掛載輸出目錄(direct 模式,直通)
10[[bind]]
11mode = "direct"
12source = "/tmp/agent-output"
13destination = "/output"
14
15# GitHub API 憑證(Bearer token)
16[[cred]]
17url = "https://api.github.com/"
18methods = ["GET"]
19kind = "bearer"
20api_key_env = "GITHUB_TOKEN"
21
22# OpenAI API 憑證
23[[cred]]
24url = "https://api.openai.com/v1/"
25methods = ["POST"]
26kind = "bearer"
27api_key_env = "OPENAI_API_KEY"
28
29# MCP server 整合:agent 可在 shell 中用 Lua require() 呼叫 MCP tool
30[[mcp]]
31name = "my-tools"
32command = "/path/to/mcp-server"
33args = ["--stdio"]

在 Python 中載入:

 1import strands_shell
 2
 3# 從 TOML 載入——明確指定的參數會覆蓋 TOML 中的值
 4shell = strands_shell.Shell(
 5    config_file="sandbox.toml",
 6    timeout=60.0,  # 覆蓋 TOML 中的 timeout(如果有的話)
 7)
 8
 9# 執行指令
10out = shell.run("ls /workspace")
11print(out.stdout)
12
13# MCP tools 可透過 Lua 存取
14out = shell.run('lua -e \'local t = require("my-tools"); print(t.some_tool("arg"))\'')

4.4 File Operations API(檔案操作 API)

除了 shell 指令,Shell 物件也提供直接的檔案操作方法,不需要透過指令字串:

 1import strands_shell
 2
 3shell = strands_shell.Shell(
 4    binds=[
 5        strands_shell.Bind("/my/project", "/workspace", mode="copy"),
 6    ],
 7    limits=strands_shell.Limits(
 8        max_file_size=10 * 1024 * 1024,  # 10 MB per file
 9        max_output=1 * 1024 * 1024,       # 1 MB stdout cap
10        max_inodes=10_000,                 # 最多 10,000 個檔案
11        max_fds=128,                       # 最多 128 個 file descriptor
12    ),
13)
14
15# 直接寫入檔案(不需要 echo > file)
16shell.write_file("/workspace/note.txt", b"Hello, World!")
17
18# 直接讀取檔案(回傳 bytes)
19data = shell.read_file("/workspace/note.txt")
20print(data.decode())  # Hello, World!
21
22# 列出目錄(回傳 FileInfo 物件列表)
23entries = shell.list_files("/workspace")
24for entry in entries:
25    kind = "DIR" if entry.is_dir else "FILE"
26    size = entry.size if entry.size is not None else "-"
27    print(f"  [{kind}] {entry.name}  ({size} bytes)")
28
29# 刪除檔案
30shell.remove_file("/workspace/note.txt")
31
32# 錯誤處理——使用 typed exception hierarchy
33try:
34    shell.read_file("/workspace/nonexistent.txt")
35except strands_shell.FileNotFoundError as e:
36    print(f"File not found: {e.path}")  # 可直接 except FileNotFoundError
37except strands_shell.FileTooLargeError as e:
38    print(f"File too large: {e.message}")
39except strands_shell.PermissionDeniedError as e:
40    print(f"Permission denied: {e.path}")

設計亮點ShellError 的子類別同時繼承了 Python 標準函式庫的例外類別——FileNotFoundError 同時是 strands_shell.FileNotFoundErrorbuiltins.FileNotFoundError,所以 except FileNotFoundError 就能捕捉到,不需要特殊的 import。


5. 進階功能 (Advanced Features)

5.1 Custom Kernel 後端

os::Kernel 是一個 Rust trait,你可以實作自己的 Kernel 來替換預設的 VfsKernel。這讓 Strands Shell 可以對接各種後端:

1use std::sync::Arc;
2use strands_shell::Shell;
3use strands_shell::os::Kernel;
4
5// 例如:S3-backed kernel,檔案系統存在 S3
6// 或 database-backed kernel,metadata 存在資料庫
7fn from_custom_kernel(kernel: Arc<dyn Kernel>) -> Shell {
8    Shell::with_kernel(kernel)
9}

可能的 custom kernel 場景:

  • S3-backed filesystem:agent 直接讀寫 S3 bucket
  • Database-backed filesystem:metadata 和權限存在 PostgreSQL
  • Audit kernel:包裝 VfsKernel,記錄所有 I/O 操作到 audit log

5.2 Lua 5.4 整合

當 shell scripting 不夠用時,Strands Shell 內嵌了 Lua 5.4 runtime。Lua scripts 可以存取 shell 的環境變數和 VFS:

 1# 在 shell 中執行 Lua
 2lua -e 'for i = 1, 10 do print("Item " .. i) end'
 3
 4# 使用 Lua 處理 JSON(比 jq 更適合複雜邏輯)
 5curl -s https://api.example.com/data | lua -e '
 6  local json = require("json")
 7  local data = json.decode(io.read("*a"))
 8  for _, item in ipairs(data.results) do
 9    print(item.name .. ": " .. item.score)
10  end
11'

MCP-to-Lua bridge:如果在 TOML 設定中宣告了 [[mcp]] server,這些 server 會在 Lua 中以 module 形式出現。使用 require("server-name") 就能呼叫 MCP tool:

1# 假設 TOML 中設定了 name = "my-tools" 的 MCP server
2lua -e '
3  local tools = require("my-tools")
4  local result = tools.search_documents("query string")
5  print(result)
6'

5.3 Resource Limits (資源限制)

Strands Shell 提供多層資源限制來防止 runaway agent (失控的 agent):

 1import strands_shell
 2
 3shell = strands_shell.Shell(
 4    limits=strands_shell.Limits(
 5        max_output=1 << 20,    # 1 MB stdout 上限(防止無限輸出填滿記憶體)
 6        max_file_size=10 << 20, # 10 MB 單檔上限
 7        max_fds=128,            # 最多 128 個 file descriptor
 8        max_bg_jobs=8,          # 最多 8 個背景工作
 9        max_pipeline=16,        # pipeline 最多 16 段
10        max_input=1 << 20,      # 1 MB stdin 上限
11        max_inodes=10_000,      # 最多 10,000 個 inode(檔案 + 目錄)
12        max_depth=64,           # 遞迴深度上限
13    ),
14    timeout=30.0,  # 每個指令 30 秒超時
15)

這些限制是 best-effort (盡力而為) 的——它們能抓住大多數失控狀況,但不是為了對抗主動嘗試突破的攻擊者。對於 multi-tenant (多租戶) 或 adversarial (對抗性) 工作負載,應該在 container 或 microVM 內執行 Strands Shell。

5.4 SSRF Guard (SSRF 防護)

curl 指令預設阻擋 private IP ranges (私有 IP 位址範圍):

  • RFC1918:10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
  • Link-local:169.254.0.0/16(包括 AWS IMDS 169.254.169.254)
  • Loopback:127.0.0.0/8

公開 URL 預設允許通過。使用 allowed_urls 可以額外允許特定的內部 host。

5.5 Multi-tenant 使用模式

Shell instance 是 single-owner (單一擁有者) 的。如果你服務多個 agent,為每個 session 建立一個新的 Shell:

 1# 每個 agent session 建立獨立的 Shell
 2# 建構成本極低——只是記憶體內的資料結構
 3def create_agent_shell(session_id: str, project_path: str) -> strands_shell.Shell:
 4    return strands_shell.Shell(
 5        binds=[
 6            strands_shell.Bind(project_path, "/workspace", mode="copy"),
 7            strands_shell.Bind(f"/tmp/output/{session_id}", "/output", mode="direct"),
 8        ],
 9        timeout=30.0,
10        limits=strands_shell.Limits(max_output=1 << 20),
11    )

5.6 WASM Target

Strands Shell 可以編譯為 WASM,在瀏覽器或 WASM runtime 中執行:

1# 需要 wasi-sdk >= 32
2./scripts/build-wasm.sh --release

WASM target 限制:不支援 PyO3 binding、不支援 MCP server、不支援 --config 檔案載入。WASM instance 在獨立的 linear memory (線性記憶體) 中執行,提供天然的隔離。


6. Agent 可呼叫性分析 (Agent Callability)

6.1 MCP Interface

Strands Shell 提供完整的 MCP server,透過 stdio 上的 JSON-RPC 協定通訊。任何支援 MCP 的 AI 工具(Claude Code、Cursor、Windsurf 等)都可以直接使用。

暴露的 Tool

Tool 名稱輸入輸出說明
shellcommand: string, timeout_ms?: numberstdout + stderr + exit_code執行 shell 指令
read_filepath: string, offset?: int, limit?: inttext / image / blob讀取 VFS 檔案
write_filepath: string, content: string確認訊息寫入 VFS 檔案
list_dirpath: string目錄列表列出 VFS 目錄
1{
2  "mcpServers": {
3    "shell": {
4      "command": "uvx",
5      "args": ["strands-shell", "--config", "sandbox.toml", "--mcp"]
6    }
7  }
8}

6.2 Python SDK

直接在 Python agent 程式碼中使用,無需 MCP overhead:

 1# 與 Strands Agents SDK 整合
 2from strands import Agent
 3import strands_shell
 4
 5shell = strands_shell.Shell(
 6    binds=[strands_shell.Bind("/project", "/workspace", mode="copy")],
 7)
 8
 9# 作為 tool 提供給 agent
10def shell_tool(command: str) -> str:
11    """Execute a shell command in the sandboxed environment."""
12    out = shell.run(command)
13    if out.status != 0:
14        return f"Error (exit {out.status}): {out.stderr}"
15    return out.stdout

6.3 Node.js SDK

1import { Shell } from '@strands-agents/shell'
2
3const shell = await Shell.create({
4    binds: [{ source: '/project', destination: '/workspace', mode: 'copy' }],
5    timeout: 30000,
6})
7
8const out = await shell.run('grep -rn "TODO" /workspace')
9console.log(out.stdout)

6.4 Rust Library

1use strands_shell::Shell;
2
3let mut shell = Shell::builder()
4    .bind("/project", "/workspace")
5    .timeout(std::time::Duration::from_secs(30))
6    .build()?;
7
8let output = shell.run("grep -rn TODO /workspace").await;
9println!("exit {}: {}", output.status, output.stdout);

7. 與生態系的關係 (Ecosystem Relationships)

7.1 Strands Agents 生態系全景

Strands Agents 由 AWS 開源,包含 13 個 repository,形成一個完整的 AI agent 開發平台:

Repository說明與 Shell 的關係
sdk-python (main SDK)Python SDK,model-driven agent 框架Shell 作為 tool 被 SDK agent 呼叫
sdk-typescriptTypeScript SDKShell 的 Node.js binding 可直接整合
tools官方 tool 集合Shell 與 tools 互補——tools 是 high-level,Shell 是 low-level
shell本 repoagent 的安全 shell 執行環境
agent-sopNatural language workflow可透過 Shell 執行 SOP 中的 shell 步驟
agent-builderTerminal-based agent builder使用 Shell 提供安全的指令執行
evalsAgent 評估框架可在 Shell sandbox 中執行待評估的 agent
harness-sdkAgent harness SDKShell 可作為 harness 的 sandbox 後端
mcp-serverStrands Agents 文件 MCP server與 Shell 的 MCP server 互補——一個提供文件,一個提供執行
docs官方文件包含 Shell 的使用指南
samples範例 agents展示如何在 agent 中使用 Shell
devtoolsCI/CD 共用工具Shell repo 使用這些共用 workflow
extension-template擴充套件模板可參考建立 Shell 的自定 command

7.2 整合架構


flowchart LR
    subgraph "Strands Agents 生態系"
        sdk["SDK
(Python / TypeScript)"] tools["Tools
(高階 tool 集)"] shell["Shell
(安全 shell 環境)"] sop["Agent SOP
(自然語言工作流)"] evals["Evals
(評估框架)"] harness["Harness SDK
(生產環境 harness)"] mcp_doc["MCP Server
(文件查詢)"] end sdk --> tools sdk --> shell sdk --> sop sop --> shell evals --> shell harness --> shell shell -.->|"MCP protocol"| mcp_doc style shell fill:#ff6b6b,color:#fff

7.3 Shell 在 agent 工作流中的定位

Strands Shell 填補了生態系中一個關鍵的缺口:安全的低階執行環境

  • Tools 提供高階抽象(「搜尋文件」、「呼叫 API」)
  • Shell 提供低階能力(「執行任意 shell 指令」),但帶有安全護欄
  • Agent SOP 定義工作流程,其中的 shell 步驟可以安全地在 Shell sandbox 中執行
  • Evals 可以在 Shell sandbox 中執行被評估的 agent code,確保評估環境的隔離

8. 優缺點分析 (Strengths & Limitations)

8.1 優勢

面向優勢細節
效能亞毫秒冷啟動沒有 container/VM overhead,純記憶體操作
安全模型Default-deny + Kernel mediation每一個 I/O 都必經 Kernel trait,沒有繞過的途徑
憑證安全Agent 永遠看不到 secretPer-URL injection,redirect 不重新注入
跨平台macOS + Linux + WASM不依賴 Docker daemon 或雲端服務
多語言Rust + Python + Node.js + WASM一份 Rust 原始碼編譯出所有 binding
MCP 原生內建 MCP server與任何 MCP client 零設定整合
指令豐富58 個內建指令涵蓋 agent 最常用的 coreutils 子集
狀態持久跨 run() 保持狀態cwd、env、function 都保留,像真正的 interactive session
Lua 整合內嵌 Lua 5.4當 shell scripting 不夠用時的 escape hatch

8.2 限制

面向限制說明
非安全沙箱它是 mediation layer,不是安全沙箱不防護 memory-safety exploit、timing side-channel
指令覆蓋不是完整的 GNU coreutils部分指令的 flag 支援有缺口
不支援 fork/exec無法執行任意二進位只能使用內建的 58 個指令 + Lua
多租戶每個 Shell 是 single-owner多租戶場景需要額外的 container/VM 隔離
Resource limitsBest-effort抓失控 agent,但不防主動攻擊
Async 需求需要 tokio LocalSetRust API 需要在 tokio::task::LocalSet 中執行
WASM 限制功能子集不支援 MCP、config file、PyO3

8.3 安全模型的邊界

需要特別強調的是:Strands Shell 不是 container 或 VM。它的安全模型假設:

  • 威脅模型:「我的 agent 不應該存取我沒有明確允許的東西」
  • 不適用:「不受信任的租戶執行任意程式碼」

對於後者,建議在 container 或 microVM 執行 Strands Shell,獲得雙層防護。


9. 實戰應用場景 (Real-world Use Cases)

9.1 場景一:AI Coding Agent 的安全開發環境

情境:你正在建立一個 AI coding agent,它需要閱讀專案原始碼、執行測試、修改檔案、提交 git commit。但你不想讓它存取你的 SSH key、.env 檔案、或其他專案。

 1import strands_shell
 2
 3# 建立隔離的開發環境
 4dev_shell = strands_shell.Shell(
 5    binds=[
 6        # 只掛載 src/ 目錄(不是整個專案根目錄)
 7        # 排除 .git/, .env, node_modules/
 8        strands_shell.Bind("/home/user/project/src", "/workspace/src", mode="copy"),
 9        strands_shell.Bind("/home/user/project/tests", "/workspace/tests", mode="copy"),
10        strands_shell.Bind("/home/user/project/package.json", "/workspace/package.json", mode="copy"),
11        # 輸出目錄——agent 的修改寫在這裡
12        strands_shell.Bind("/tmp/agent-output", "/output", mode="direct"),
13    ],
14    credentials=[
15        strands_shell.Cred(url="https://registry.npmjs.org/", env_var="NPM_TOKEN"),
16    ],
17    allowed_urls=["https://registry.npmjs.org/"],
18    timeout=60.0,
19    limits=strands_shell.Limits(max_output=2 << 20),
20)
21
22# Agent 工作流
23out = dev_shell.run("grep -rn 'TODO\\|FIXME\\|HACK' /workspace/src")
24print("Found issues:", out.stdout)
25
26out = dev_shell.run("find /workspace/src -name '*.ts' | wc -l")
27print("TypeScript files:", out.stdout.strip())
28
29# 將修改寫到輸出目錄(host 可見)
30dev_shell.run("cp /workspace/src/index.ts /output/index.ts.fixed")

9.2 場景二:安全的 API 整合測試

情境:你的 agent 需要與多個外部 API 互動(GitHub、OpenAI、自家 API),但你不想讓 agent 拿到原始的 API key,也不想讓它存取未授權的 endpoint。

 1import strands_shell
 2
 3api_shell = strands_shell.Shell(
 4    credentials=[
 5        strands_shell.Cred(url="https://api.github.com/", env_var="GITHUB_TOKEN"),
 6        strands_shell.Cred(url="https://api.openai.com/v1/", env_var="OPENAI_API_KEY"),
 7        strands_shell.Cred(url="https://internal-api.company.com/", env_var="INTERNAL_TOKEN"),
 8    ],
 9    allowed_urls=[
10        "https://api.github.com/",
11        "https://api.openai.com/v1/",
12        "https://internal-api.company.com/",
13    ],
14    timeout=30.0,
15)
16
17# Agent 可以安全地呼叫 API——token 自動注入,agent 看不到值
18out = api_shell.run('''
19    curl -s https://api.github.com/repos/strands-agents/shell \
20    | jq '{name: .name, stars: .stargazers_count, language: .language}'
21''')
22print(out.stdout)
23
24# 嘗試存取 IMDS(AWS metadata endpoint)→ SSRF guard 阻擋
25out = api_shell.run('curl http://169.254.169.254/latest/meta-data/')
26print(f"IMDS blocked: exit code {out.status}")
27
28# 嘗試列印環境變數中的 token → 看不到
29out = api_shell.run('echo $GITHUB_TOKEN')
30print(f"Token visible? '{out.stdout.strip()}'")  # 空的

9.3 場景三:批次文件處理管線

情境:你需要讓 agent 處理一批 CSV / JSON 檔案——篩選、轉換、彙整——然後輸出結果。

 1import strands_shell
 2
 3pipeline_shell = strands_shell.Shell(
 4    binds=[
 5        strands_shell.Bind("/data/input", "/input", mode="copy"),
 6        strands_shell.Bind("/data/output", "/output", mode="direct"),
 7    ],
 8    timeout=120.0,
 9    limits=strands_shell.Limits(
10        max_file_size=50 << 20,  # 50 MB per file
11        max_output=5 << 20,       # 5 MB stdout
12    ),
13)
14
15# 使用 shell pipeline 處理資料
16pipeline_shell.run('''
17    # 找出所有 CSV 檔案
18    find /input -name "*.csv" | while read f; do
19        echo "Processing: $f"
20        # 取出 header + 符合條件的行
21        head -1 "$f" > /output/$(basename "$f" .csv)_filtered.csv
22        grep -i "active" "$f" >> /output/$(basename "$f" .csv)_filtered.csv
23    done
24''')
25
26# 用 jq 處理 JSON
27pipeline_shell.run('''
28    cat /input/data.json | jq '
29        .records
30        | map(select(.status == "active"))
31        | sort_by(.score)
32        | reverse
33        | .[0:10]
34    ' > /output/top10.json
35''')
36
37# 產生摘要報告
38out = pipeline_shell.run('''
39    echo "=== Processing Summary ==="
40    echo "Input files: $(find /input -type f | wc -l)"
41    echo "Output files: $(find /output -type f | wc -l)"
42    echo "Total output size: $(find /output -type f -exec wc -c {} + | tail -1)"
43''')
44print(out.stdout)

附錄 A:完整指令清單

Builtins (25 個)

alias, cd, : (colon/noop), echo, export, find, getopts, hash, local, lua, printf, pwd, read, set, shift, test / [, trap, type, umask, unset, wait, xargs

Isolated Commands (33 個)

basename, cat, chmod, cp, curl, cut, date, dirname, echo, env, false, grep, head, jq, ln, ls, mkdir, mktemp, mv, pwd, readlink, rm, rmdir, sed, sleep, sort, tail, tee, touch, tr, true, uniq, wc

Shell 語法支援

  • Pipes (|)、redirections (>, >>, <, 2>&1)
  • Subshells ($(...), backticks)
  • Variables ($VAR, ${VAR:-default})
  • Control flow (if/then/else/fi, while/do/done, for/do/done, case/esac)
  • Functions(func() { ...; }
  • Background jobs (&) with wait
  • Here documents (<<EOF)

附錄 B:安全設定最佳實踐 Checklist

  • 使用 mode="copy" 掛載原始碼(而非 mode="direct"
  • 只 bind 必要的子目錄(/project/src 而非 /project/
  • 不要 bind 含有 .git/.envnode_modules/ 的目錄
  • 明確列出 allowed_urls(不要用 https:// 來允許所有 HTTPS)
  • 設定 timeout(建議 30 秒)
  • 設定 max_output(建議 1 MB)
  • 使用 env_var 而非 token 來提供 credential(避免硬編碼)
  • 對於 multi-tenant 場景,在 container 內執行 Shell
  • 每個 agent session 建立獨立的 Shell instance

附錄 C:參考資源