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+ 個常用指令(grep、sed、jq、curl、find 等),完全不需要 fork、exec 或任何 system call (系統呼叫)。
1.2 誰開發的
Strands Shell 是 AWS 開源的 Strands Agents 生態系的一部分。Strands Agents 是一個完整的 AI agent 開發平台,由 13 個 repository 組成,涵蓋 SDK、工具集、評估框架、文件等各個層面。Shell 是這個生態系中負責「安全 shell 執行環境」的核心元件。
1.3 為什麼重要
| 特性 | Docker | 雲端 Sandbox | Strands Shell |
|---|---|---|---|
| 冷啟動 | ~200ms | ~1s (網路) | <1ms |
| 隔離方式 | Container namespace | MicroVM | In-process VFS |
| 網路控制 | iptables / sidecar | 平台政策 | URL allowlist + SSRF guard |
| 機密管理 | Env vars (agent 可讀) | 平台特定 | Per-request inject,agent 不可見 |
| 安裝方式 | Docker daemon | API key + 網路 | pip install strands-shell |
| 支援平台 | Linux | 僅雲端 | macOS, Linux, WASM |
最值得注意的三個設計亮點:
- <1ms 冷啟動:沒有 container、沒有 VM,就是記憶體內的資料結構。每個 request 建立一個新的 Shell instance 是預期的使用模式。
- Credential injection (憑證注入):agent 永遠看不到 API key 的值。Kernel 在每次 HTTP request 時自動注入憑證,即使 redirect (重新導向) 也不會重新注入,防止 credential leakage (憑證外洩)。
- 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 API | Shell, ShellBuilder, Output | Builder-based 進入點 |
| Kernel | os::Kernel | 抽象所有 OS 操作的 trait |
| VFS Kernel | vfs_kernel | 預設 kernel,由 in-memory VFS 支撐 |
| VFS | vfs | In-memory 檔案系統(含 host bind mount) |
| Executor | exec | Shell 直譯器(parsing、expansion、pipeline) |
| Commands | commands, 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::Fifo、CharDevice、BlockDevice:特殊裝置節點
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/ 下。包括:cd、export、alias、set、shift、local、read、echo、printf、test、trap、umask、unset、wait、xargs、find、getopts、hash、type、lua、pwd 等 25 個。
Isolated Commands (隔離指令):不修改 shell 狀態,定義在 src/commands/ 下。每個指令使用 #[command("name")] proc-macro 註冊。包括:grep、sed、cat、head、tail、jq、curl、cp、mv、rm、mkdir、ls、sort、cut、tr、uniq、wc、tee、touch、chmod、ln、basename、dirname、readlink、mktemp、rmdir、sleep、date、env、true、false、echo、pwd 等 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_coderead_file:讀取 VFS 中的檔案(支援文字、圖片、二進位)write_file:寫入檔案到 VFSlist_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.FileNotFoundError 和 builtins.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 名稱 | 輸入 | 輸出 | 說明 |
|---|---|---|---|
shell | command: string, timeout_ms?: number | stdout + stderr + exit_code | 執行 shell 指令 |
read_file | path: string, offset?: int, limit?: int | text / image / blob | 讀取 VFS 檔案 |
write_file | path: string, content: string | 確認訊息 | 寫入 VFS 檔案 |
list_dir | path: 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-typescript | TypeScript SDK | Shell 的 Node.js binding 可直接整合 |
| tools | 官方 tool 集合 | Shell 與 tools 互補——tools 是 high-level,Shell 是 low-level |
| shell | 本 repo | agent 的安全 shell 執行環境 |
| agent-sop | Natural language workflow | 可透過 Shell 執行 SOP 中的 shell 步驟 |
| agent-builder | Terminal-based agent builder | 使用 Shell 提供安全的指令執行 |
| evals | Agent 評估框架 | 可在 Shell sandbox 中執行待評估的 agent |
| harness-sdk | Agent harness SDK | Shell 可作為 harness 的 sandbox 後端 |
| mcp-server | Strands Agents 文件 MCP server | 與 Shell 的 MCP server 互補——一個提供文件,一個提供執行 |
| docs | 官方文件 | 包含 Shell 的使用指南 |
| samples | 範例 agents | 展示如何在 agent 中使用 Shell |
| devtools | CI/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 永遠看不到 secret | Per-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 limits | Best-effort | 抓失控 agent,但不防主動攻擊 |
| Async 需求 | 需要 tokio LocalSet | Rust 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 (
&) withwait - Here documents (
<<EOF)
附錄 B:安全設定最佳實踐 Checklist
- 使用
mode="copy"掛載原始碼(而非mode="direct") - 只 bind 必要的子目錄(
/project/src而非/project或/) - 不要 bind 含有
.git/、.env、node_modules/的目錄 - 明確列出
allowed_urls(不要用https://來允許所有 HTTPS) - 設定
timeout(建議 30 秒) - 設定
max_output(建議 1 MB) - 使用
env_var而非token來提供 credential(避免硬編碼) - 對於 multi-tenant 場景,在 container 內執行 Shell
- 每個 agent session 建立獨立的 Shell instance
Comments