跳到主要內容
Lab Grimoire
TW EN
請喝咖啡
雙腦共治看板:Claude Code 動手改,Claude Desktop 即時看
動手實作

雙腦共治看板:Claude Code 動手改,Claude Desktop 即時看

Agent 工作流實戰 · 第 13/14 篇
本頁目錄

你的看板,為什麼總在「好用」跟「好看」之間二選一?

我有一個跑了大半年的任務看板,上面有 39 張 active 卡片,橫跨研發、計畫書、客戶開發、論文。它一開始只是一份 Obsidian Kanban 的 Markdown,後來我把它拆成結構化的卡片檔,每張卡一個 .md,frontmatter 記著 status、owner、優先級、到期日。

這個決定讓我後來省了很多事,因為看板既然是純文字,我的 Claude Code 就能一次讀完 39 張卡,批次改狀態、把完成的卡片搬去歸檔,而且任何會讀檔的 agent 都動得了它。

但有個東西一直卡著我,那就是 它很醜。

在終端機裡看這份看板,像在看一具報表的屍體,沒有分欄、沒有顏色,逾期的也不會標紅。我想要的是那種打開就看到全局、滑鼠點得動、改完即時更新的戰情室,可是漂亮的儀表板通常綁死在某個 SaaS 裡,你的資料被鎖進別人的資料庫,換工具就搬不走。於是可程式化跟好看,好像永遠只能挑一個。

直到我把這兩件事拆開:資料歸資料,畫面歸畫面,中間用 MCP 接起來。這麼一拆,同一份看板就能被 Claude Code 在終端機裡程式化地改,同時被 Claude Desktop 用 Live artifacts 即時、漂亮、可互動地呈現。我甚至能在儀表板上直接按一張卡,填進度、按封存,底層檔案就跟著被改掉,因為兩邊看的始終是同一個真相

這篇就講這套「雙腦共治」怎麼搭,而且不空談架構,我會把實際做出來的那塊晨間戰情室整個拆給你看。

我把這套架構叫做雙腦共治看板:它把「資料層」和「呈現層」徹底分開,資料以純文字卡片儲存,可被任何 AI Agent 程式化讀寫,呈現則透過 Claude Desktop 的 Live artifacts 即時渲染,兼顧美觀與互動,中間再用 MCP 連接器把兩端橋接起來,共享同一份資料來源。

資料/橋接/呈現三層架構

先看成品:一塊「晨間戰情室」長怎樣

先給你看終點,也就是我用 Claude Desktop 的 Live artifacts 做出來的儀表板,一打開長這樣:

  • 本週衝刺:從 Kanban 撈出 status 為「本週」的卡,依緊急度排序,逾期跳色。
  • 今日行程:拉今天的 Google Calendar 事件,含起訖時間。
  • 未讀信件:抓 Gmail 收件匣未讀,顯示寄件者、主旨、摘要。
  • 完整 Kanban 看板:全部卡片,可依 status × type 雙維度篩選。每張卡右上有個勾。

最關鍵的是那個勾,點下去會彈出一個小視窗,你可以填「本次行動」「下一步」「調整緊急度」,按確認之後,底層的 .md 卡片真的被改掉。 或者直接按「封存」,卡片就被搬到歸檔區,畫面當場刷新。

儀表板寫回閉環示意

這塊儀表板同時吃三個不同的 connector,一個是我本機的 Kanban MCP,另外兩個是雲端的 Google Calendar 跟 Gmail,它們在同一塊 Live artifact 裡和平共處。下面就拆它是怎麼兜出來的。

為什麼好看的 SaaS 看板是陷阱

你可能會問,Trello、Notion、Linear 不就又好看又能用嗎?確實好用,但它們有一個共同的代價:你的資料住在它家。

SaaS 看板的問題不在功能,而在它把你的資料鎖在自己家裡。哪天你想讓自己的 AI Agent 自動整理任務,要嘛它有開 API,你還得學它那套 API,要嘛它根本沒開,於是你的 39 張卡就被關在別人的後台裡。

更麻煩的是多 agent 這件事。我現在手上不只一個 AI 助手,Claude Code 跑重活,有時候也叫別的 agent 幫忙,而如果看板資料鎖在某個 SaaS,每接一個新 agent 就要重寫一次串接。

所以我要的東西很明確:

  • 資料要是我的:純文字、放在我的目錄、版本控制得到。
  • 任何會讀檔的 agent 都能直接管它,不用學專屬 API。
  • 但呈現要漂亮、即時、能互動,不能又是終端機裡那種死板的報表。

這三條看起來互相打架,其實只要分層,就能全部成立。

三層架構:資料、橋接、呈現

整套系統拆成三層,每層職責單一,所以換掉任何一層,另外兩層都不受影響。

呈現層    Claude Desktop / Live artifacts   (美觀、即時、互動、可寫回)
            ↑↓  window.cowork.callMcpTool()
橋接層    MCP 連接器                          (ycbio-kanban 本機 + Calendar/Gmail 雲端)
            ↑↓
資料層    cards/*.md + frontmatter           (純文字、可版控、任何 agent 可讀寫)

關鍵在於:資料層完全不知道呈現層長怎樣。 它只是一堆 Markdown 卡片;呈現層同樣不碰資料的儲存格式,只透過 MCP 拿到當下的資料再渲染。中間那層 MCP 是唯一的橋,而且是一座雙向橋,資料能往上流去呈現,指令也能往下流來改檔。

下面逐層拆。

資料層:純文字看板,多 agent 的共同語言

資料層的核心很樸素,就是一個 cards/ 資料夾,底下分 active/(未完成)跟 archive/(已完成,按季歸檔),每張卡片是一個獨立的 .md,所有欄位都寫在 YAML frontmatter:

---
id: 2026-Q2-icNAD-東南亞市場開發
title: icNAD+ 東南亞市場開發
status: 進行中
type: 商業化
owner: YCBio
urgency: high
# 其餘必填欄位省略
---

## 背景
東南亞 NAD+ 保健市場切入...

純文字之所以關鍵,是因為它是所有 agent 的最大公約數,Claude Code 讀得到,Codex、Copilot 也讀得到,連你自己用文字編輯器都改得動。它沒有專屬格式、沒有資料庫鎖定,而且 git diff 看得到每一次改動。

接著是一個關鍵設計:凍結列舉(frozen enum)。我有一份 schema.yml,把 status、urgency、type 這些欄位的合法值直接寫死:

# schema.yml(節錄)
status:   [本週, 積極推進, 等待, 進行中, 低活動, 完成]
urgency:  [urgent, high, medium, low]
type:     [論文, 補助, IRB, 平台, icNAD, 合作, 商業化, 內部, 個人]

這一步看起來多餘,其實是多 agent 協作的命脈。當好幾個 agent 都會寫這份看板,一旦沒有凍結列舉,A agent 寫 status: 進行中、B agent 寫 status: doing、C agent 寫 status: 處理中,三個月後你的看板欄位就會亂成一團。凍結列舉就是大家共用的一本字典,所有 agent 只能從清單裡挑,看板才不會被寫爛。

資料層的設計哲學一句話:讓資料蠢一點,蠢資料才通用。 把聰明留給上層。

橋接層:MCP 怎麼接,兩種接法

資料層是一堆檔案,但 Claude Desktop 不會自己去翻你的硬碟,中間需要一座橋,而這座橋就是 MCP(Model Context Protocol)連接器,它讓 AI 能讀寫你指定的本機資源。

接法有兩種,一種求快,一種求穩。

接法一:通用 filesystem MCP(30 秒上手)

最快的方式是用官方的 filesystem server,指向你的看板資料夾。打開 ~/Library/Application Support/Claude/claude_desktop_config.json,加一塊:

{
  "mcpServers": {
    "workspace": {
      "command": "/Users/你/.local/bin/npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem",
               "/絕對路徑/到你的/Kanban"]
    }
  }
}

它給的是通用讀寫,能讀任何檔、也能寫任何檔,優點是零建置,缺點則是它很笨。它不懂你的 schema,如果 AI 一時手滑把 status 寫成一個不存在的值,filesystem MCP 不會攔,它照寫,於是你的凍結列舉形同虛設。

小坑先講:command 建議用 絕對路徑。Claude Desktop 啟動 MCP 時的 PATH 很乾淨,如果你的 npx 裝在非標準位置(例如 ~/.local/bin),只寫 "npx" 會找不到,寫全路徑最保險。

接法二:專用 Kanban MCP(正式版,會防呆)

進階一點的做法,是寫一個懂看板的 MCP server。我自己這套就是一個 TypeScript 寫的小 server,叫 ycbio-kanban,它不開放亂寫檔,只開放六個看板專用的工具

工具 做什麼
kanban_list_cards 列出 active 卡片,可依 status / type / owner / 緊急度篩選
kanban_get_card 取單張卡的完整內容
kanban_update_card 改 frontmatter 欄位(status、urgency、next_step、last_action…)
kanban_create_card 建新卡,自動產生 id
kanban_archive_card 把完成的卡搬到 archive/{年}-Q{季}/
kanban_get_schema 回傳 schema.yml 的合法列舉值

設定長這樣(注意是 node 跑編譯後的 dist/):

{
  "mcpServers": {
    "ycbio-kanban": {
      "command": "node",
      "args": ["/絕對路徑/kanban-mcp-server/dist/index.js"],
      "env": { "KANBAN_ROOT": "/絕對路徑/到你的/Kanban" }
    }
  }
}

兩者的差別,在於它把 schema 變成程式邏輯。 kanban_update_cardurgency 欄位用 z.enum 鎖死四個合法值,填錯直接被擋回來,而 kanban_get_schema 讓 AI 隨時問「status 有哪些合法值」。這跟 Hook 守門系統 是同一個思路:不靠 AI 的自律,靠程式化的硬約束。

不過我得誠實說,這道硬約束目前只做到一半。statustype 這兩欄我還是宣告成自由字串,合法值只寫在工具描述裡給 AI 看,程式並不會擋。真正咬得住的只有 urgency。所以「寫不出垃圾資料」這句話,現在還是靠 AI 讀了描述自己遵守,不是靠程式擋。這是我還沒補完的部分。

至於兩種接法怎麼選,看這張表就清楚:

面向 filesystem MCP 專用 Kanban MCP
上手時間 30 秒 需寫 + 建置(約 1-2 小時
schema 驗證 ❌ 無 ✅ 寫入前檢查
工具語意 通用讀寫檔 看板專用動詞
適合場景 個人快速試水 多 agent 正式協作
寫壞資料的風險

我的建議是:先用 filesystem MCP 把流程跑通。確認 Live artifacts 真的能呈現。再花一兩小時升級成專用 MCP。 別一開始就鑽進寫 server,先驗證整條鏈走得通再說。我那塊晨間戰情室最後接的是專用的 ycbio-kanban,因為它要從 UI 寫回,而寫回這件事沒有 schema 驗證,我不敢放心交給畫面。

兩種 MCP 接法對照

呈現層:Live artifacts 真正怎麼綁 connector

前面兩層都是地基,真正讓人眼睛一亮的,是 Claude Desktop 在 Cowork 模式下的 Live artifacts。它的官方定義是:

Create dynamic artifacts that stay up-to-date using live data from your connectors.

翻成白話,會自己保持更新的動態 artifact。資料源是你的 connector(也就是 MCP)。 一般 artifact 是死的快照,生成那一刻什麼樣,之後就什麼樣;Live artifact 則是活的,它綁定你的 connector,你一重抓,它就拿到最新資料重新渲染。

至於它怎麼知道要綁哪些 connector,答案藏在 artifact 檔案最上面一塊 meta 宣告。我這塊儀表板的開頭長這樣:

<script type="application/json" id="cowork-artifact-meta">
{
  "mcpTools": [
    "mcp__ycbio-kanban__kanban_list_cards",
    "mcp__ycbio-kanban__kanban_update_card"
  ],
  "mcpServerNames": ["ycbio-kanban", "ycbio-kanban"]
}
</script>

看懂這塊,你就懂 Live artifacts 的核心了:它白紙黑字宣告「我要用這幾個 MCP 工具」。本機的 stdio server(ycbio-kanban)給的是友善名字,雲端 connector(Calendar、Gmail)則是一串 UUID,三種來源並列,一塊儀表板全包。

真正呼叫資料的那行:window.cowork.callMcpTool

宣告完工具後要拿到資料,靠的是 Live artifact 的 JavaScript,透過 Cowork runtime 注入的那座橋來呼叫:

// 同一呼叫形狀:工具全名 + 參數
const raw  = await window.cowork.callMcpTool(
  'mcp__ycbio-kanban__kanban_list_cards', { limit: 100 });
const cal  = await window.cowork.callMcpTool(
  'mcp__b331c650-...__list_events', { /* 時間範圍 */ });
const mail = await window.cowork.callMcpTool(
  'mcp__31baa064-...__search_threads', { query: 'is:unread in:inbox' });

就這麼直白,window.cowork.callMcpTool(工具名, 參數) 回傳資料之後,你愛怎麼渲染就怎麼渲染,分欄、跳色、做統計,全是你的 HTML/CSS 自由發揮。

一個真實踩坑:回傳格式有三種形狀

這個沒人會先告訴你:callMcpTool 的回傳依工具不同,可能是三種形狀之一,我吃過虧後才寫了一個保險絲:

// (a) 字串 (b) structuredContent (c) content[].text 信封
function extractMcpResult(raw) {
  if (typeof raw === 'string') return JSON.parse(raw);
  if (raw?.structuredContent !== undefined) return raw.structuredContent;
  if (Array.isArray(raw?.content) && raw.content[0]?.text)
    return JSON.parse(raw.content[0].text);
  return raw ?? {};
}

互動不是只讀:從儀表板直接改卡、封存

callMcpTool 不只讀,也能呼叫寫工具。 每張卡右上那個勾,點下去就是這套:

// 寫回與封存:只留呼叫形狀
await window.cowork.callMcpTool(
  'mcp__ycbio-kanban__kanban_update_card',
  { id, last_action, next_step, urgency });
await window.cowork.callMcpTool(
  'mcp__ycbio-kanban__kanban_archive_card', { id });
await loadKanban(); // 寫完立刻重抓

流程是個閉環:畫面寫回 MCP。MCP 改 .md。改完重抓。畫面更新。 在儀表板填進度、改下一步,底層 frontmatter 就真的變了。專用 MCP 下 urgency 只能填合法值,畫面再用下拉選單擋一次。

這也是為什麼呈現層要接專用 Kanban MCP 而不是 filesystem:讀沒差,但一旦要,就得靠 schema 守門。

安全紅線:connector 資料別直接塞進 innerHTML

做這塊儀表板時被安全掃描抓到的真實漏洞,很隱蔽也很危險。顯示未讀信,我一開始這樣寫:

// ❌ 危險:主旨直接拼進 innerHTML
body.innerHTML = threads.map(t =>
  `<div>${t.messages[0].subject}</div>`).join('');

信件主旨內容由寄信的人決定。任何人都能寄主旨是 <img src=x onerror="把你的資料偷走"> 的信;你一開儀表板,innerHTML 就解析執行。畫面握著 Gmail、Calendar、Kanban 連線,中標等於交鑰匙。

這是 XSS(跨站腳本攻擊)。email 主旨、寄件者、摘要、行事曆標題全是外部不可控輸入,直接塞 innerHTML 就是自己開洞。解法是寫跳脫 helper,外部資料進畫面前先過一遍:

// ✅ 安全寫法:外部字串先進 esc()
function esc(s) {
  return String(s ?? '').replace(/[&<>"']/g, c =>
    ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
}
body.innerHTML = threads.map(t =>
  `<div>${esc(t.messages[0].subject)}</div>`).join('');

esc() 把危險字元轉成 HTML 實體,<img> 就只會當純文字顯示。

鐵律:任何來自 connector 的資料(尤其 email、行事曆),進 innerHTML 前一律 esc() 或改用 .textContent,不要拼字串。

更陰的一點:Live artifact 是 AI 生成的。 下次重做一版,它可能又吐出沒跳脫的版本。治本是重生 prompt 就寫死「connector 資料進 innerHTML 前必須 HTML-escape」。

共治分工:誰動手、誰守規矩、誰展示

「雙腦共治」的精髓,是讓不同的大腦各做它最擅長的事,但都對著同一份資料

角色 工具 職責 比喻
操盤手 Claude Code(終端機) 批次改卡、遷移、跑腳本、git 版控、寫 MCP server 後場工頭
幫手 其他 agent(Codex / Copilot…) 在各自情境下讀寫同一份卡片 輪班同事
守門員 專用 Kanban MCP 強制所有寫入合法 品管
戰情室 Claude Desktop Live artifacts 即時呈現全局,並可從 UI 寫回 展示窗兼操作台

實際一天大概是:早上開晨間戰情室掃逾期、行程、急信;單張進度直接在儀表板勾、填兩句、確認。要動大的就切 Claude Code 批次改狀態與 next_step、commit,回到儀表板重抓即可。

改用左腦(Claude Code,精準、可程式化、批次)。看與輕量操作用右腦(Claude Desktop,直覺、好看、點得動)。 中間靠 MCP 同步,兩邊永遠是同一個真相,不用複製貼上,也不會有兩份走鐘的資料。

而且因為資料層是中立的純文字,哪天我想換掉其中一顆腦,資料層完全不用動,換一個會讀檔的 agent 就好。呈現層、操作層都可以抽換。資料層是錨。

從零搭建:5 步,一個下午

Step 1:設計資料層(約 30 分鐘

cards/active/cards/archive/,定 frontmatter 欄位,用 schema.yml 凍結 status/urgency/type,再手建三五張真卡確認夠用。

Step 2:接 filesystem MCP 跑通鏈路(約 5 分鐘

把 filesystem server 加進 claude_desktop_config.json(看板根目錄用絕對路徑),設完 Cmd+Q 全退再重開。

Step 3:驗證 Live artifact 能讀(約 10 分鐘

Cowork → Live artifacts,確認 connector 清單看得到,再叫它生一塊 Kanban。這一步是試金石。 看到即時看板,就代表鏈通了。

Step 4:升級成專用 Kanban MCP(約 1-2 小時

流程通了再寫專用 server:六個看板動詞,重點是 kanban_update_card 寫前驗 schema;建置成 dist/ 後把 config 換成 node server 並重啟,換來「能從 UI 安全寫回」。

Step 5:做出有互動的戰情室(約 30 分鐘

Live artifact 接上 kanban_update_cardkanban_archive_card,加「標進度/封存」小窗,prompt 寫死connector 資料要 esc();其他 agent 也指同一份 cards 就完工。

常見踩坑

下面 6 個 坑,先知道就能先閃。

坑 1:Live artifacts 只在 Cowork 模式。 你在一般 Chat 分頁找不到它,它在 Cowork 的側邊欄,記得先切過去。

坑 2:本機 stdio MCP 沒被 connector 清單列到。 雲端帳號(Gmail、Calendar)一定會出現在 connector 來源裡,但本機 stdio MCP 能不能被列,務必在 Step 3 親眼確認。沒列到,就還停在「能讀但不能即時呈現」的階段。

坑 3:connector 資料直接進 innerHTML(XSS)。 前面整段講過,email 主旨、行事曆標題都是外人可控的,所以一律 esc()。這是會出人命的坑。

坑 4:callMcpTool 回傳三種形狀。 純字串、structuredContentcontent[].text 信封都可能出現,用前面那個 extractMcpResult 統一接,不然你會卡在「明明有資料卻 parse 失敗」。

坑 5:filesystem MCP 把 frontmatter 寫壞。 通用讀寫沒有 schema 驗證,所以只要要寫回就升級到專用 MCP,能早點升就早點升。

坑 6:資料夾在 iCloud,多裝置同步延遲。 cards 放在 iCloud 路徑時,A 裝置改完,B 裝置的 Live artifact 可能還沒同步到,所以看到舊資料別嚇到,等 iCloud 同步完再重抓就好。

想更深入?

這套「資料與呈現分離」的思路,其實是整個 Agent 工作流設計的縮影。想看記憶、Skill、Hook 怎麼用同樣的分層哲學兜起來,從 CLAUDE.md 設計哲學 開始。接著 三層記憶架構多平台記憶同步。串完你就懂為什麼「讓底層蠢一點」反而讓整個系統更強。

另外我整理了一份《Claude Code 快速上手速查表》。安裝、CLAUDE.md 配置、記憶系統基礎、MCP 設定、常用指令,一頁搞定。

免費下載速查表

下一篇:把看板變成真.即時儀表板:本機 file watcher 實作

常見問題

Live artifact 是「即時」到什麼程度?秒級嗎?

它是「會保持更新」,不是毫秒級推播。底層資料變了,它在重抓時反映最新狀態。我的儀表板放了一個「重新整理」按鈕,一按就重跑 loadKanban / loadCal / loadMail。從 UI 寫回的操作則是寫完自動重抓。對任務看板這種分鐘級的東西,綽綽有餘。

我一定要會寫 MCP server 嗎?

純看,不用。filesystem MCP 零建置就能讀。但要從儀表板安全寫回,建議寫專用 MCP,把 schema 驗證放進去。寫回沒守門員我不敢交給畫面。

從畫面改卡,跟 Claude Code 改卡,會打架嗎?

不會,只要約定好。兩邊都透過同一份 cards。但盡量別在同一秒改同一張卡(後寫蓋前寫)。我的習慣:輕量單張更新走儀表板,批次重活走 Claude Code。錯開就沒事。

資料層放純文字,不會比資料庫慢嗎?

對個人到小團隊的看板(幾十到幾百張卡),純文字完全不是瓶頸。換來的是通用性、可版控、可被任何 agent 讀寫。卡片量真的爆到上萬,再談資料庫不遲。

為什麼不直接用 Notion / Linear 的 API 就好?

可以。但資料住它家。換 agent 要重學 API。搬不走。純文字 + MCP 的好處是資料是你的、格式中立、git 看得到歷史、任何會讀檔的 agent 都能接。主導權在你手上。

這套能搬到別的 AI 工具嗎?

資料層跟橋接層完全通用。任何支援 MCP 的客戶端都能接同一個 connector。任何會讀本機檔的 agent 都能管同一份 cards。只有「Live artifacts 呈現」這塊是 Claude Desktop 專屬。但那只是呈現層。抽換掉也不影響資料。

覺得這篇有幫助?

追蹤以收到新的 AI × 生醫研究筆記:

或請我喝杯咖啡,讓新內容持續產出。

☕ 請我喝杯咖啡