OpenAI 在 4 月 15 日更新了 Agents SDK,加入了 sandbox 隔離、Harness/compute 分離、Manifest 工作區描述、Capabilities 分層。看完技術文件後我的第一反應是「這跟我們在做的事情不一樣」,第二反應是「但裡面有幾個結構性概念可以偷」。
這篇記錄我們從中借了什麼、怎麼落地到 openclaw-workspace-template v3.0.0,以及為什麼大部分東西我們選擇不抄。
兩個系統的定位差異
先把前提講清楚:OpenAI Agents SDK 跟我們的 workspace template 解決的是完全不同的問題。
| OpenAI Agents SDK | 我們的 workspace template | |
|---|---|---|
| 目標使用者 | 企業,多租戶 SaaS | 個人,單使用者 |
| 執行環境 | 雲端 sandbox(Modal / E2B / Cloudflare / Vercel) | 本機 Mac / Linux,直接 filesystem access |
| 權限模型 | Tool calls 在 unprivileged container 裡跑,隔離網路和 secret | 跟使用者同權限,能碰 git / cron / Telegram / Obsidian |
| State | serialize_session_state() / resume(),snapshot 整個 workspace | 檔案系統就是 state,git 就是 snapshot |
| Memory | 內建 Memory() capability,session close 自動 summarize → consolidate | 自建 MemPalace:hall-tagged journal + 主題筆記 + weekly reflection + knowledge graph |
OpenAI 在解的是「怎麼讓 agent 安全可靠地跑在生產環境」。我們在解的是「怎麼讓一個人的知識和自動化系統持續累積和整合」。拿來直接比就像比 AWS Lambda 跟家裡的 crontab。
所以 sandbox 隔離、multi-tenant、container snapshot 這些我們完全不需要。我們的 agent 能直接 git commit、改 crontab、發 Telegram 通知、rebuild knowledge graph——把它塞進 sandbox 等於砍掉核心價值。
但有三個結構性概念跟 runtime 無關,純粹是「怎麼描述和組織你的系統」的問題。這些值得借。
借鏡 1:Manifest → workspace.spec
OpenAI 怎麼做
OpenAI 的 Manifest 是一個 Python object,宣告式描述 agent 的工作區應該長什麼樣:
Manifest(
entries=[
GitRepo(url="...", path="repo"),
LocalDir(host_path="~/notes", workspace_path="notes"),
S3Mount(bucket="my-kb", workspace_path="kb"),
],
environment={"PYTHONPATH": "/workspace/repo"},
)
跑 agent 前,sandbox 照這份 spec 組出環境。換機器、換 provider,同一份 Manifest 就能重建。
我們之前怎麼做
bootstrap.sh 裡面一堆 mkdir -p 和 copy_tree 呼叫:
mkdir -p "$WORKSPACE_PATH/memory"
mkdir -p "$WORKSPACE_PATH/notes/00-Inbox"
mkdir -p "$WORKSPACE_PATH/notes/01-Projects/Active"
# ...13 個目錄
copy_tree "$SCRIPT_DIR/templates"
copy_tree "$SCRIPT_DIR/scripts" "scripts"
copy_tree "$SCRIPT_DIR/cron" "cron"
要知道「工作區應該有什麼」,得讀整份 bash。
我們怎麼改
新增 templates/workspace.spec,44 行的 line-based DSL:
# workspace.spec — Declarative workspace layout
copy_tree templates
copy_tree scripts scripts
copy_tree cron cron
dir memory
dir notes/00-Inbox
dir notes/01-Projects/Active
dir notes/01-Projects/Archive
dir notes/02-Areas
dir notes/03-Resources
dir notes/04-Archive
dir .learnings
dir scripts
dir .claude/skills
dir cron/logs
dir reference
dir tmp
bootstrap.sh 裡新增一個 process_workspace_spec() function 讀這份檔案。條件邏輯(welcome flag、chmod、next-steps banner)留在 bash。
為什麼不用 YAML?不想加 parser dependency。這份 spec 只有兩個 verb(dir 和 copy_tree),純 bash 的 parameter expansion 就能解析。遇到不認識的 verb 會直接 exit 1 並印出 workspace.spec:42: unknown verb 'bogus'。
驗證方式:用舊版 bootstrap 建一個 workspace,再用新版建一個,find . | sort | diff 兩邊。結果完全一致(97 個路徑)。
借鏡 2:Capabilities → settings.capabilities.toml
OpenAI 怎麼做
OpenAI 的 Agents SDK 把 agent 的能力分成幾個 Capability 層:
Capabilities(
Shell(),
Filesystem(), # apply_patch + view_image
Skills(),
Memory(),
Compaction(),
)
預設是 Filesystem + Shell + Compaction。要加能力就顯式 opt-in。
我們之前怎麼做
settings.json 裡有一個 flat array:
"allow": [
"Bash(python3 scripts/*)",
"Bash(bash scripts/*)",
"Bash(git status:*)",
"Bash(git diff:*)",
"Read(*)",
"Grep(*)",
"Write(memory/*)",
"Edit(notes/*)"
]
25 個 entry 混在一起,看不出「這個 agent 到底能幹嘛」的大圖。
我們怎麼改
新增 settings.capabilities.toml 作為 source of truth,分成 6 個 capability bucket:
[capabilities.run_scripts]
description = "Execute project-owned scripts under scripts/"
allow = [
"Bash(python3 scripts/*)",
"Bash(bash scripts/*)",
]
[capabilities.inspect_git]
description = "Read-only git inspection"
allow = [
"Bash(git status:*)",
"Bash(git diff:*)",
"Bash(git log:*)",
"Bash(git show:*)",
"Bash(git branch:*)",
]
[capabilities.write_memory]
description = "Append/edit memory palace artifacts"
allow = [
"Write(memory/*)",
"Write(MEMORY.md)",
"Edit(memory/*)",
"Edit(MEMORY.md)",
]
# ...
tools/build-settings.py(stdlib tomllib,零外部 dependency)讀 TOML、生成 settings.json,同時保留 hooks 區塊不動。跑兩次產出 byte-identical 的 JSON。
Permission set 完全沒變:25 個 entry,0 新增 0 移除。這不是加權限,是把既有權限整理成人類可讀的分組。
借鏡 3:serialize_session_state → save/load YAML schema
OpenAI 怎麼做
client.serialize_session_state() 把 agent 的 session 狀態序列化成結構化資料,client.resume() 在新的 sandbox 裡恢復。重點是:序列化的格式是有 schema 的,load 端可以靠固定欄位做型別化處理。
我們之前怎麼做
/save 指令產出一個 markdown 檔到 tmp/<slug>.md,裡面是自由格式的 H2 sections:
# Session State: ...
## Context
(自由發揮)
## Completed
(自由發揮)
## Pending
### High
- ...
/load 讀這份檔案,靠 Claude 的語意理解來解析。大部分時候可以用,但「哪些檔案被改過」「哪些 pending 是 high priority」這些資訊藏在 prose 裡面,跨 session 會 drift。
我們怎麼改
加入 YAML frontmatter 作為機器可解析的 schema:
---
slug: refactor-espresso-notes
saved_at: 2026-04-16T14:30:00+08:00
project: cc-memory-project
title: Refactor espresso dial-in notes
summary: >
把散落在各處的 espresso dial-in 筆記整理成 per-bean template。
completed:
- task: "建立 bean template"
files: ["notes/02-Areas/Coffee/bean-template.md:1"]
decision: "用 frontmatter field 而非 heading hierarchy"
pending:
- priority: high
task: "現有 5 篇 bean note 還沒套 template"
files: ["notes/02-Areas/Coffee/ethiopia-guji.md"]
blocker: null
suggested_fix: "逐篇跑 regex replace + 人工校對"
---
10 個 top-level key 全部 required,空值寫 null 或 [],不能省略 key。/load 先解析 frontmatter 做結構化摘要(pending 幾個 high / medium / low、touched 哪些檔案),再對 files[] 做 glob 檢查確認檔案還在。
舊格式的 save 檔(沒有 frontmatter)走 legacy fallback,讀 H2 sections,標記 (legacy schema)。
沒抄的東西
列一下明確選擇不做的:
- Sandbox isolation:我們的 moat 就是深度整合本機環境。隔離 = 砍功能。
- Manifest cloud mounts(S3 / GCS / Azure Blob):state 全在本機 + git,不需要。
- OpenAI Memory() capability:它是自動 summarize → consolidate 到
MEMORY.md。我們有自建的 MemPalace(hall tag journal、weekly reflection、pattern promotion、knowledge graph),功能複雜一個數量級。套它等於退化。 - Harness/compute 分離:Claude Code 本來就是我們的 harness,它跟 filesystem 的耦合是 feature 不是 bug。
- Multi-tenant 架構:我們是單使用者系統。為不存在的需求加 isolation tax 不值得。
實際效果
改完之後的差異是維護體驗:
| 以前 | 現在 |
|---|---|
| 要知道 workspace 長什麼樣,讀 255 行 bash | 讀 44 行 workspace.spec |
| 要知道 agent 有什麼權限,看 25 行 flat array 然後心算 | 看 TOML 6 個 bucket,每個有 description |
settings.json 手動改,改完忘記改了什麼 | 改 TOML → 跑 build script → commit 兩份 |
/save 產出自由格式 prose,/load 靠語意猜 | frontmatter 有 schema,/load 做型別化摘要 + 檔案存在檢查 |
| bootstrap 完告訴你「edit IDENTITY/USER/SOUL/TOOLS」 | bootstrap 完告訴你「type hi」,agent 一步一步問你 |
都不是大改動。workspace.spec 多了 44 行,build-settings.py 121 行,TOML 82 行,save/load schema 是 prompt 指令的修改。整個 PR 加起來 375 行新增。
但這些改動讓下次要動 template 的人(通常是三個月後的我自己)不用重新讀 bash 才知道系統長什麼樣。
結尾
OpenAI Agents SDK 在做的是幫企業把 agent 生產化的通用工具鏈。我們在做的是幫一個人極致整合生活和工作的垂直系統。兩者的 runtime 和安全需求差很遠,但「怎麼描述你的系統」這個問題是共通的。
Manifest 教我們把 workspace layout 從 bash 裡抽出來變成宣告式 spec。Capabilities 教我們把 flat permission list 分層成可 reason about 的 bucket。serialize_session_state 教我們把跨 session 的 handoff 從 prose 收緊成有 schema 的結構。
三個都不是 rocket science,但都是「痛了才知道要做」的那種改善。趁看到別人做了,順手補上。
