用 Claude Code mod 做一個「工作佇列」面板:哪條線在跑、誰剛交件、什麼在等我決定

mod 是什麼
mod 是一種 Claude Code plugin。它用 JavaScript/TypeScript 寫事件處理函式,可以改 Claude Code 的畫面與行為。
官方定義原文:「A mod is a plugin that changes how Claude Code looks and behaves.」
| 項目 | 內容 |
|---|---|
| 推出日期 | 2026-10-01,CHANGELOG v2.1.287 加入 |
| 預設開啟 | 官方文件寫「Mods are on by default」,終端機 v2.1.287 以上預設開啟 |
| API 狀態 | 仍在變動。官方 GitHub 的 mods/ README 標「Early access」,寫明 API 可能在版本之間改變 |
| 本文依據 | Claude Code v2.1.302。新版可能要調整 |
兩個用語先講清楚,官方文件也這樣分:
hook:mod 裡的事件處理函式。例如「session 開始時做某事」。
settings hook:寫在 settings.json 的舊式 hook,是另一個功能。本文說的 hook 都是前者。
官方 Agent View 看程序,這個 mod 看工作
官方已有 Agent View(claude agents)。它列出同一台機器上的背景 session:哪個在跑、哪個在等你回覆。官方文件標它為 research preview。
Agent View 看的是「程序」。我想看的是「工作」:一條工作線今天跑了哪些 task,哪個失敗了;哪些問題卡在等我決定,提問方建議怎麼做。
這些資訊跟程序在不在跑無關。task 可能由 claude -p 腳本、排程、別的工具產生。
所以這個 mod 不去找程序。它只讀兩個檔:queue.jsonl 在每個 task 開始、結束各寫一行;decisions.json 放目前等你決定的事。
任何腳本都能寫這兩個檔。檔案就是介面。
這個 mod 做什麼
| 功能 | 怎麼出現 | 內容 |
|---|---|---|
| Pane(面板) | 輸入 /queue 打開,在逐字稿旁邊 | 在跑的 task、最近完成的 6 個、等你決定的事 |
| 提示上方一行(官方稱 AbovePrompt) | 有 task 在跑或有待決時自動出現 | 例如「● 2 個 task 在跑(docs frontend) · 2 件等你決定 · /queue 看細節」 |
| /queue 指令 | 打開面板,同時回一段文字 | 跟面板相同的內容。沒有畫面的 claude -p 也看得到這段文字 |
| 定時重讀 | 預設每 15 秒 | 重讀兩個檔,面板跟著更新 |

/queue 是 mod 註冊的 slash command。官方文件說,mod 的指令直接跑函式,不經過 Claude 的回合。
這個 mod 不產生資料。你的腳本或 agent 要自己寫這兩個檔。
資料格式
| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
| ev | "start" 或 "end" | 是 | task 開始或結束 |
| id | string | 是 | 同一次執行的 start 與 end 用同一個 id |
| lane | string | start 必填 | 工作線名稱,例如 backend |
| task | string | start 必填 | task 的一句話描述 |
| at | string | 是 | ISO 8601 時間,要帶時區 |
| error | boolean | 否 | 只用在 end;true 代表失敗 |
有 start、沒有 end 的 task 算「在跑」。解析失敗的行會略過,例如寫到一半的行。
從 shell 腳本寫一行:
echo '{"ev":"start","id":"t7","lane":"docs","task":"update FAQ","at":"'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'"}' >> .work-queue/queue.jsonl| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
| id | string | 是 | 識別碼 |
| title | string | 是 | 一句標題 |
| ask | string | 是 | 要你回答的問題 |
| rec | string | 否 | 提問方的建議 |
| lane | string | 否 | 哪條工作線在問 |
{
"items": [
{ "id": "d1", "lane": "backend", "title": "Rate limit value",
"ask": "Allow 5 or 10 login attempts per minute?",
"rec": "10, then lower it if abuse shows up in logs" }
]
}讀不到某個檔時,面板與 /queue 會寫「找不到 <路徑>」。mod 不會假裝沒事。
三個路徑與間隔可以在 /config 改(plugin 的 userConfig):queueFile、decisionsFile、refreshSeconds。相對路徑從 session 的工作目錄算起。
程式怎麼寫:三段關鍵程式
完整程式只有一個檔:hooks/register.tsx,約 200 行。下面挑三段,每段講一個概念。
第一段:register 是 mod 的進入點,在這裡掛 hook。
export const register: Register = (on, options) => {
const queueFile = String(options.queueFile ?? '.work-queue/queue.jsonl')
const decisionsFile = String(options.decisionsFile ?? '.work-queue/decisions.json')
const refreshMs = Math.max(5, Number(options.refreshSeconds ?? 15)) * 1000
on('session.start', async ($, e, next) => {
await $.command.register({
name: COMMAND,
description: '打開工作佇列面板:各工作線在跑什麼、等你決定的事',
})
await reload($, queueFile, decisionsFile)
$.clock.every(refreshMs, () => reload($, queueFile, decisionsFile))
return next(e)
})
// ……其餘 hook
}概念:mod 是一組 hook。Claude Code 載入 mod 時呼叫 register。
on(事件名, 處理函式) 掛一個 hook。options 是使用者在 /config 設的值。$ 是 mod 能用的 API;本 mod 用到讀檔、註冊指令、計時、開面板、讀寫狀態。
next(e) 把事件交回原本的流程。本 mod 只是「順便」做事,不改變 session 開始的行為。
reload 讀兩個檔,把結果寫進 mod 自己的狀態(state)。我第一版把 reload 寫在 register 裡面,validate 不通過。引擎要求接收 $ 的函式宣告在檔案頂層,路徑改用參數傳入。
第二段:ui.render Pane,把資料畫成面板。
on('ui.render', { component: 'Pane', requestId: PANE }, async ($, e) => {
const { Box, Text } = $.ui.resolve(e)
const list = await read($, runs)
const asks = await read($, decisions)
const now = await $.clock.now()
const running = list.filter(r => r.endedAt === null)
return (
<Box flexDirection="column">
<Text bold>工作線</Text>
{running.map(r => (
<Text>
<Text color="green">● {r.lane}</Text> {r.task}
<Text dimColor> {ago(r.startedAt, now)}</Text>
</Text>
))}
{/* ……最近完成、等你決定 */}
</Box>
)
})概念:畫面也是 hook。Claude Code 要畫某個元件時,會發出 ui.render 事件。
第二個參數是過濾條件,這裡只接「id 為 work-queue 的 Pane」。$.ui.resolve(e) 拿到這個介面能用的元件,例如 Box、Text。回傳 JSX,Claude Code 就把它畫出來。
提示上方那一行用同一招,條件改成 { component: 'AbovePrompt' }。沒有東西要顯示時,它回傳 next(e),讓原本的畫面照常出現。
第三段:command.run 處理 /queue 指令,有畫面就開面板,沒畫面就回文字。
on('command.run', { command: COMMAND }, async $ => {
await reload($, queueFile, decisionsFile)
try {
await $.ui.open({ id: PANE, title: TITLE })
} catch {
// 沒有畫面的 session(claude -p、雲端)開不了面板;文字結果照樣回。
}
const now = await $.clock.now()
return { text: summaryText(await read($, runs), await read($, decisions), now, await read($, missing)) }
})概念:指令要替「沒有畫面」的地方留後路。claude -p 與雲端 session 會跑 hook,但不畫面板。
$.ui.open 在沒畫面的地方會失敗,所以包在 try 裡。不管面板開不開得了,指令都回傳 { text }。有畫面時,你同時看到面板和文字;沒畫面時,你至少拿得到文字。
安全:mod 不在沙盒裡
先講結論:裝任何 mod 之前,先跑 claude plugin validate,看 hooks: 和 calls: 兩行。
原因是 mod 用你的權限執行。官方文件原文:「Mods aren't sandboxed.」官方文件也寫明,mod 能讀環境變數裡的 API key,也能自動核准工具呼叫。
claude plugin validate 不執行 mod。它只讀原始碼,列出 mod 掛了哪些事件、呼叫了哪些 API。
下面是本 mod 的實際輸出。我只把本機絕對路徑換成相對路徑:
Validating plugin manifest: work-queue-pane/.claude-plugin/plugin.json
❯ types ./types/index.d.ts declares on $: nothing (no EngineInterface member)
❯ types ./types/index.d.ts declares state: work-queue-pane.runs, work-queue-pane.decisions, work-queue-pane.missing
Validating hooks: work-queue-pane/hooks/hooks.json
❯ ./register.tsx hooks: session.start, command.run{command=queue}, ui.render{component=Pane, requestId=work-queue}, ui.render{component=AbovePrompt}
❯ ./register.tsx gating hook without .catch: command.run{command=queue}
❯ ./register.tsx calls: $.clock.every, $.clock.now, $.command.register, $.fs.read (via reload), $.state.get, $.state.set, $.ui.open, $.ui.resolve
❯ ./register.tsx state writes: work-queue-pane.decisions, work-queue-pane.missing, work-queue-pane.runs
❯ ./register.tsx state reads: work-queue-pane.decisions, work-queue-pane.missing, work-queue-pane.runs
ℹ Advice (does not change the verdict):
❯ work-queue-pane/README.md: This README has no line that installs "work-queue-pane" from a marketplace. Add the install line, which works in one step on Claude Code 2.1.275 or later. Validate the folder that holds its marketplace.json to have <owner>/<repo> filled in, and the name its marketplace lists it under.
/plugin install work-queue-pane --marketplace <owner>/<repo>
✔ Validation passed| 輸出行 | 意思 |
|---|---|
| declares on $: nothing | 這個 mod 沒有替 $ 加新的 API 給別的 mod 用 |
| declares state | 它宣告三格自己的狀態:task 清單、待決清單、找不到的檔 |
| hooks: | 只掛四個 hook。session.start 註冊 /queue、讀檔、啟動定時重讀;command.run{command=queue} 只接 /queue;ui.render 的 Pane 與 AbovePrompt 只畫自己的面板與那一行。清單裡沒有 tool.call 之類的工具事件,所以它不會攔或核准任何工具呼叫 |
| gating hook without .catch | 這是提示,不是錯誤。/queue 由這個 mod 接手處理,validate 提醒它沒有接例外。會失敗的 $.ui.open 已經包在 try 裡 |
| calls: | 最該看的一行,列出 mod 實際呼叫的每個 API。$.fs.read (via reload) 是唯一碰檔案的呼叫,而且只讀,讀的是設定裡指定的兩個檔。其餘是計時、註冊指令、開面板、拿畫面元件、讀寫自己的狀態。清單裡沒有寫檔、連網、跑外部程式的呼叫 |
| state writes/state reads | 只動自己名下的三格狀態,不碰別的 mod 的狀態 |
| Advice | 建議 README 補一行 marketplace 安裝指令,不影響結果。這個 mod 目前用 zip 發布,所以沒有這一行 |
如果你看到的 calls: 多出別的 API,代表檔案被改過。不要安裝。
自己驗:從下載到看到畫面
需要 Claude Code v2.1.287 以上。
1. 下載 work-queue-pane-0.1.0.zip:
下載 work-queue-pane 0.1.0 原始碼與範例資料(ZIP)這個 zip 以 MIT 授權發布,全文在 zip 內的 LICENSE。
2.對雜湊值。輸出要等於下面這串;不相等就停下來,不要往下做:
shasum -a 256 work-queue-pane-0.1.0.zip
# 576144e65fb89ea24372fc73ded52baa2ee460e2ec01d4cc8483fcdfabc62dff3. 解壓。zip 內有外層資料夾,會解出 work-queue-pane/:
unzip work-queue-pane-0.1.0.zip4. 跑 validate,對照上一節的輸出:
claude plugin validate ./work-queue-pane5. 建一個試用資料夾,放進範例資料:
mkdir queue-demo
cp -R work-queue-pane/examples/.work-queue queue-demo/
cd queue-demo6. 在試用資料夾載入 mod,啟動 Claude Code:
claude --plugin-dir ../work-queue-pane7. 看提示上方那一行。輸入 /queue,打開面板。
範例資料有 3 條工作線、2 個 task 在跑、2 件待決。範例的時間是固定的,所以「跑多久」會顯示很大的數字。這是正常的。
要接你自己的資料,讓你的腳本寫 .work-queue/queue.jsonl 與 .work-queue/decisions.json。或在 /config 把路徑指到別處。
| 介面 | hook 會跑 | 畫面會顯示 |
|---|---|---|
| 終端機 claude(含編輯器內建終端機、JetBrains plugin) | 是 | 是,需 v2.1.287 以上 |
| 桌面 App 的 Code 分頁 | 是 | 是,終端機專用元件除外;需 v2.1.286 以上 |
| 桌面 App 的 WSL session | 否 | 否 |
| VS Code 擴充的聊天面板 | 是 | 擴充版本 2.1.299 以上,且 session 要能取得 feature flag |
| claude -p、Agent SDK | 是 | 否 |
| 雲端 session | 是(plugin 要能帶到雲端) | 否 |
看不到畫面的地方,用 /queue 的文字結果。在含 .work-queue/ 的目錄執行 claude -p "/queue",會印出完整文字結果。完整指令是 claude -p "/queue" --plugin-dir <mod 資料夾>。
本文的圖是在 pty 裡執行終端機版 Claude Code,再用終端模擬器重繪而成。桌面 App 與 VS Code 的顯示,我沒有實測。
限制
面板只顯示最近 30 個 task、最近完成的 6 個。
「跑多久」用本機時鐘算。寫檔的機器時鐘不準,顯示也會不準。
0.1.0 版的畫面文字是繁體中文。
下一篇
寫入 queue.jsonl 的通常是排程腳本。排程跑 agent 會遇到的坑,見下面這篇。task 失敗時記得寫 "error": true,面板才看得到。
排程跑 AI Agent,我踩過的三個坑:exit 0 不代表成功參考資料
- work-queue-pane 0.1.0 原始碼與範例資料(ZIP) / Source and sample data
- Claude Code 官方文件:Mods overview(定義、介面表、安全、validate;查閱 2026-10-17)
- Claude Code 官方文件:Agent View(標示 research preview;查閱 2026-10-17)
- Claude Code CHANGELOG(v2.1.287 加入 Claude Mods;查閱 2026-10-17)
- GitHub release v2.1.287(查閱 2026-10-17)
- 官方部落格〈Claude Code mods〉(2026-10-01;查閱 2026-10-17)
- 官方 mods/ README(Early access 說明;查閱 2026-10-17)