沙箱
沙箱是在你自己的機器上啟動的容器,裡面只有你自己的代理程式、Motir CLI 和你的儲存庫副本——別無他物。你自帶代理程式憑證,並以唯讀方式掛載;迴圈在容器內執行,因此行為失當的代理程式只能觸及你的工作樹,而無法觸及機器上的其他部分。
開始之前
- Docker,已在執行。 同時建置了
linux/amd64和linux/arm64兩種版本,因此 Apple Silicon 是原生支援,沒有任何模擬。沒有建置步驟——直接拉取。 - 你的代理程式自己的登入狀態,就在這台機器上。 它的憑證掛載是唯讀的,所以容器可以使用某個登入狀態,卻不能更新。你會遇到的例外是 macOS 上的 Claude Code:它把權杖儲存在登入鑰匙圈中,因此沒有可掛載的檔案,需要改為在容器 內部 登入
claude——映像為它提供了可寫的設定目錄,登入狀態就落在那裡。(Antigravity 同理——你選擇它時,第 2 步會說明。) - 你的工作區根目錄——包含各個儲存庫副本的那個資料夾。 一個專案通常橫跨多個儲存庫,迴圈會在所有這些儲存庫中執行。
你的電腦
~/work/ ← start the container from HERE ├── motir-core/ ← a checkout └── motir-ai/ ← another
你使用哪個代理程式?
也支援
或
下面的每條指令都針對 Claude Code。切換後,會重寫 第 1、2 和 2b 步 中的標籤和憑證掛載——也就是它們出現的三處。
設定
共五步。每一步只做一件事。
拉取適用於你的代理程式的映像
指令
沒有建置步驟——映像按代理程式設定檔分別釋出。
pull
docker pull ghcr.io/moooon-b-v/motir-sandbox:claude
在工作區根目錄啟動容器
指令
請在 包含 各個儲存庫副本的資料夾中執行,而不是在其中任何一個儲存庫裡。
run
docker run -it --rm --pull=always \ -v "$PWD:/workspace" \ -v motir-auth:/home/node/.config/motir \ -v "$HOME/.claude:/home/node/.claude:ro" \ ghcr.io/moooon-b-v/motir-sandbox:claude
改用 VS Code? 下面的第 2a–2c 步取代本步。之後的所有內容,兩種方式都相同。
安裝 Dev Containers 擴充
在編輯器中
可以在「擴充」檢視中安裝,或透過命令選擇區——macOS 上按 ⇧⌘P,其他系統按 Ctrl+Shift+P,三個平台都可以按 F1——然後選擇 Extensions: Install Extensions。這三步裡有兩步要在命令選擇區中完成,所以現在就把它固定下來很值得。
建立開發容器設定
指令
在你要掛載的資料夾中執行。一次貼上即可:它會建立
.devcontainer資料夾,並把檔案寫入其中。不要嘗試透過檔案選擇器建立它們——Finder 和大多數圖形介面的選擇器都不接受以點開頭的名稱,而且拒絕時不會告訴你原因。你的機器 — 在你掛載的資料夾中
mkdir -p .devcontainer cat > .devcontainer/devcontainer.json <<'JSON' { "name": "Motir sandbox (Claude Code)", "image": "ghcr.io/moooon-b-v/motir-sandbox:claude", "workspaceFolder": "/workspace", "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind", "mounts": [ "source=motir-auth,target=/home/node/.config/motir,type=volume", "source=${localEnv:HOME}/.claude,target=/home/node/.claude,type=bind,readonly" ], "remoteUser": "node", "overrideCommand": true, "postStartCommand": "motir-sandbox-agent-config || true" } JSON開發容器會保留建立它時所用的映像。
--pull=always屬於第 2 步的執行指令,不屬於這條路線。要切換到目前的映像和motirCLI:1. 在你機器上的終端機裡執行第 1 步的docker pull;2. 對此資料夾執行 Dev Containers: Open Folder in Container…,這會附加視窗;3. 執行 Dev Containers: Rebuild Container,它會用你剛拉取的映像重新建立容器。「Rebuild Container」只會出現在已附加到容器的視窗中,所以必須先做第 2 步。重新建置會保留你的 Motir 登入狀態(它存放在motir-auth磁碟區上),但不會保留在容器內完成的 Claude Code 登入——請執行claude並重新登入。在容器中開啟該資料夾
在編輯器中
命令選擇區 → Dev Containers: Open Folder in Container…,然後選擇你剛剛寫入該檔案的資料夾。它的終端機就是第 2 步本會帶你進入的同一個 shell——從第 3 步繼續。
在容器內登入
指令
會輸出一個程式碼和一個 URL;在任意瀏覽器中核准即可。登入狀態會落在
motir-auth磁碟區上,所以只需做一次。在容器中
motir login
把該資料夾關聯到你的專案
指令
把
ACME換成你的專案鍵。如果你的工作區恰好只有一個專案,就省略該參數——這就是整個步驟。在容器中
motir link --project ACME
檢查——全部透過,就是本頁的終點
指令
認證、關聯、代理程式二進位檔及其憑證。只有這一步能告訴你,容器是否真的拿到了你傳給它的東西。
在容器中
motir doctor
該指令寫入的檔案
僅供參考,不是步驟——2b 已經把它寫好了。這裡提供給更願意手動建立該檔案的讀者,同時也因為 <<’JSON’ 周圍的引號起著關鍵作用:它們阻止你的 shell 在 ${localWorkspaceFolder} 和 ${localEnv:HOME} 到達檔案之前就把它們展開。這些是 Dev Containers 的替換變數,由編輯器來解析。
.devcontainer/devcontainer.json
{
"name": "Motir sandbox (Claude Code)",
"image": "ghcr.io/moooon-b-v/motir-sandbox:claude",
"workspaceFolder": "/workspace",
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind",
"mounts": [
"source=motir-auth,target=/home/node/.config/motir,type=volume",
"source=${localEnv:HOME}/.claude,target=/home/node/.claude,type=bind,readonly"
],
"remoteUser": "node",
"overrideCommand": true,
"postStartCommand": "motir-sandbox-agent-config || true"
}為什麼是這樣
設定檔選擇器改變了什麼
選擇一個代理程式會改寫三樣東西,僅此而已:映像 標籤、憑證的 -v 行,以及開發容器的 image、name 和 mounts。之所以做成一個控制項,而不是一段讓你自己去替換的文字,是因為這裡的每條指令都有「複製」按鈕,而會去複製的讀者,就是不會去讀替換說明的讀者。
並非每個設定檔都只有一個憑證目錄。opencode 有兩個,需要兩條 -v 行;antigravity 把權杖儲存在作業系統的金鑰環中,一條也不需要,改為在容器內登入;aider 繫結的是一個檔案,並從環境變數讀取模型金鑰。你選擇它們時,步驟中會有相應說明。
執行指令不會保留任何可能過時的東西
--pull=always 會在每次啟動時取得目前映像,因此已經移動的設定檔標籤無需你察覺就能到達你手中,而 --rm 意味著不會保留任何可能過時的東西。沒有單獨的「回頭再用」路徑——過去正是這一點讓人執行著比所讀頁面舊了好幾個月的 motir。你的登入狀態不受這一切影響:它寫入 motir-auth 磁碟區,該磁碟區位於容器之外,所以只需登入一次,之後每次執行都會沿用——徹底登出用 docker volume rm motir-auth。離線工作?去掉 --pull=always:它在每次啟動時都會存取映像登錄庫,所以沒有網路時執行會失敗,而不是回退到你已有的映像。以上全都是執行指令的行為。開發容器(第 2a–2c 步)會一直保留建立它時所用的映像,直到你拉取、透過 Dev Containers: Open Folder in Container… 附加,並選擇 Dev Containers: Rebuild Container。
下一步
motir run 接收一個範圍——一個工作項目、一整個使用者故事,或用 sprint 表示目前活躍的 Sprint。motir auto 則無人值守地清空就緒集合,一次處理一個工作項目,提交到一個工作階段分支上。兩者接受的每個參數都在 CLI 頁面上。
它限制了什麼——以及沒有限制什麼
在你依賴它之前值得讀一讀,因為這三項中有一項是例外,而不是保證。
- 檔案系統——受限。 容器內唯一的主機介面,是一個可寫的
/workspace和你的代理程式自己的憑證(以唯讀方式掛載)。沒有 Docker socket,沒有其他主機繫結。 - 網路——開放,這是有意為之。 每個代理程式都需要它的供應商 API,每個被排程的工作項目都需要 git 遠端儲存庫,因此映像限制的是檔案系統的影響範圍,而不是出站流量。如果你的威脅模型要求更多,請使用 Docker 自身的網路控制——容器不會阻止代理程式存取網際網路。
- 權限——無特權。 它以
node使用者(uid 1000)執行,所以寫入掛載目錄的檔案仍歸你所有,而不是 root。
環境為你提供了什麼
- 你的資料夾,已掛載。
$PWD會變成/workspace,所以執行所處理的儲存庫副本是你自己的,它產生的提交在結束時就在你的磁碟上。 - 每個工作項目一份簽出,位於 git 工作樹上。 一次執行不會編輯你目前所在的目錄樹;它會為每個工作項目新增一個工作樹,因此並行執行不會在分支簽出上發生衝突。
- 你的代理程式憑證,唯讀。 設定檔的憑證目錄以
:ro繫結掛載。容器內沒有任何東西能改寫它,它的任何內容也不會傳送給 Motir——這是自帶金鑰模式,所以代理程式的費用由你承擔,API 呼叫也不會經過我們。 - 預裝的 CLI。 映像帶有
motir以及標籤所指定的代理程式二進位檔,所以首次執行前無需安裝任何東西。 - 代理程式的輸出預設留在本機。 只有執行的生命週期會到達 Motir。傳入
--report-log會額外傳送輸出的末尾部分,使失敗的執行能在執行頁面上顯示它;除非你要求,否則它是關閉的,而且無論哪種情況,檔案內容、路徑和差異都不會被發送。
權杖可以做什麼——以及它拒絕什麼
由 motir login 產生的權杖帶有固定且收窄的授權。核准介面會顯示它,但不能更改——既不能放寬也不能收窄,因為手動收窄的授權會讓無人值守的迴圈在中途出錯。
透過裝置簽發的權杖所帶有的授權
project:browse read the project and its work items lesson:view search the recorded lessons before building lesson:reinforce record that a lesson described what went wrong work_item:edit edit the item it is running, and file a bug comment:add comment on the item ai:plan open a plan
它不帶有的那個權限是 ai:view_plan,隨之而來的拒絕是設計如此,而不是錯誤。 開啟計畫只需要 work_item:edit,所以沙箱中的執行可以開啟一個——然後在第一次追加時被拒絕,因為新增提案所檢查的正是那個權限。執行某個工作項目的執行無權重塑交給它的計畫。遇到這個拒絕時,說明代理程式做對了:它把更正記錄為留言,讓該工作項目保持已封鎖,然後停止。不會遺失任何東西,由人來決定計畫應該怎麼寫。
想讓執行更安靜時,有兩個參數可以進一步收窄:--disable-log-bug 讓代理程式不再為它在別處發現的錯誤提交錯誤工作項目(改為留下留言),--disable-replan 讓它不再為它判定有誤的工作項目提交重新規劃(改為留下留言並停止)。僅在 motir auto 上,--auto-approve-replan 走相反的方向:它會核准已提交的重新規劃並繼續迴圈,而不是停下來等你。
一次執行會產出什麼,以及在哪裡檢視
- 一個分支和一個提取要求,位於該工作項目涉及的每個儲存庫,由容器內用你的 git 憑證推送。
- 工作項目上的一個連結。 執行會宣告每個提取要求交付的是哪個工作項目,所以合併它就會推進該工作項目。工作項目頁面的「開發」面板顯示的正是這個連結,在合併時關閉工作項目的也是它——不是分支名,也不是標題。
- 狀態,隨進度更新。 執行領取工作項目時,它變為進行中;提取要求開啟時,它變為已實作。審查中由 CI 在檢查透過時寫入,已完成則由合併寫入。
- 終端機。 除非你傳入了
--report-log,否則代理程式自己的輸出會留在你的終端機中。
它無法正常運作時
找不到代理程式二進位檔
標籤與代理程式不一致。檢查你啟動的是哪個設定檔,或用 --agent <cmd> 讓執行指向另一個二進位檔。motir doctor 會在執行白白占用一次領取之前報告這一點。
代理程式已啟動,但未透過認證
憑證掛載缺失,或指向了錯誤的目錄——每個設定檔各自掛載自己的目錄。請針對你實際拉取的標籤,重新執行 docker run 那一行。
沒有可執行的內容
每個候選項都有未滿足的依賴。motir ready 會顯示就緒集合;對某個工作項目執行 motir show,會指出是什麼擋住了它。無論如何都要排程,則用 --force,且一次只能排程一個工作項目。
執行因已提交的重新規劃而停止
代理程式判定該工作項目有誤,並提出了修正後的結構。這是預期的停止:請在 Motir 中閱讀該計畫,並核准或拒絕它。若想讓無人值守的迴圈繼續,請執行 motir auto 並加上 --auto-approve-replan。
執行結束後留下了未完成的工作
工作樹和分支在你的磁碟上,位於你掛載的資料夾下——容器停止並不會把它們帶走。motir done 會收尾一個已合併的工作項目,或用 --session <branch> 收尾整個已合併的工作階段分支。
本頁不涵蓋的內容
每一條指令和每一個參數——那是 CLI,它由 CLI 自身的目錄產生,不會與之偏離。不透過 CLI、直接把代理程式串接 Motir,見 MCP 伺服器。透過 HTTP 而不是從終端機驅動同一個工作迴圈,見 API 參考。在你自己的機器之外執行沙箱,這裡尚未提供文件。(VS Code 路線已在上文記錄——這句話過去說的是另一回事,它把一個已刪除的章節當作決定記錄了下來。)