with one click
notion-plan
貼上 Notion URL,自動抓取頁面需求內容,串接 /design 建立實作計畫。
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
貼上 Notion URL,自動抓取頁面需求內容,串接 /design 建立實作計畫。
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
本 repo 自持 agent 定義目錄索引(complexity-triage / doc-reviewer / doc-updater / tdd-guide),供 design、update 等 skill 的 general-purpose subagent 呼叫時引用定義與檢查清單;本身非直接可呼叫的 skill,不會出現在指令清單中。
萬用助手 — 自動分析情境、盤點可用資源、智慧路由至最佳 agent/skill 組合,一鍵完成複雜工作流。
開發設計 — 自動盤點可用資源,透過 Plan agent 建立完整實作計畫,輸出至 plans/active/<slug>.md 供使用者確認後才進入實作。
更新知識庫 — 依序執行文件更新、審查、context 整理、pattern 提取,將本次 session 的變更沉澱為文件與知識。
產生跨 context 接手 prompt — 萃取本次對話的目標、進度、決策、未完成項目,輸出可直接貼到新 session 或 /compact 之後使用的自包含 prompt。
依 plan.md 的 Dependencies DAG 推進實作 — Python 狀態機決定下一步(非 LLM 判斷),自動串接 TaskCreate/TaskUpdate。觸發:使用者要求依 plan 推進、要求 task tracking 對齊 DAG、或抱怨 LLM 跳步漏步。
| name | notion-plan |
| description | 貼上 Notion URL,自動抓取頁面需求內容,串接 /design 建立實作計畫。 |
| allowed-tools | Bash, Read, AskUserQuestion, Skill |
| argument-hint | <Notion URL> |
貼上 Notion URL,自動擷取頁面需求內容並串接 /design 建立實作計畫。一條指令完成 Notion 抓取 → 結構化整理 → plans/active/.md 產出。
使用
playwright-cli(非 Playwright MCP):snapshot 存入.playwright-cli/*.yml按需讀取,避免每次操作自動注入 ~58KB 到 context。
使用 --profile 持久化 Notion session,避免每次重新登入。Profile 路徑:~/.playwright-cli/notion-profile
首次登入: 若偵測到需要登入(Step 2c),使用 AskUserQuestion 提供選項:
Notion 需要登入才能存取此頁面。
選項:
- 幫我開啟登入頁面 — 自動執行 headed 瀏覽器,開啟 Notion 登入頁面供手動登入
- 手動貼上內容 — 跳過瀏覽器登入,直接貼上頁面需求內容
若使用者選擇「幫我開啟」:
# 先關閉現有 session(避免衝突)
playwright-cli -s=notion close
# 以 headed 模式開啟登入頁面(notion.com 為新主網域,notion.so 會轉址至此)
playwright-cli -s=notion open "https://www.notion.com/login" --profile ~/.playwright-cli/notion-profile --headed
開啟後提示使用者:「已開啟瀏覽器,請登入 Notion。完成後告訴我。」 使用者確認登入後,用同一 session 導航至目標頁面繼續抓取。登入狀態會持久保存,後續不需重複登入。
網域遷移注意: Notion 已將主網域從
notion.so遷移至notion.com,notion.so會 301 轉址到notion.com。 登入 cookie 綁定在實際落地的網域上,因此一律以notion.com登入,避免舊notion.soprofile 的 session 在轉址後失效。
從使用者提供的引數中取得 Notion URL。支援以下格式:
| 格式 | 範例 |
|---|---|
| notion.com 頁面(新主網域) | https://www.notion.com/workspace/Page-Title-abc123 |
app.notion.com 頁面(workspace app 子網域,含 /p/ 路徑) | https://app.notion.com/p/<workspace>/Page-Title-abc123 |
| notion.so 頁面(舊網域,會轉址到 notion.com) | https://www.notion.so/workspace/Page-Title-abc123 |
| notion.site 公開頁面 | https://workspace.notion.site/Page-Title-abc123 |
| 資料庫(com / so 皆可) | https://www.notion.com/workspace/abc123?v=def456 |
| 短網址 | https://notion.com/abc123、https://notion.so/abc123 |
從 URL 提取 pageId(最後的 32 字元 hex,可能以 - 分隔或連續)— 此邏輯與網域、子網域、路徑前綴皆無關,notion.com / app.notion.com / notion.so / notion.site 共用;app.notion.com 的 /p/<workspace>/ 路徑前綴不影響抽取結果。
有效網域白名單(dot-boundary 比對): host 等於 notion.com / notion.so / notion.site,或以 .notion.com / .notion.so / .notion.site 結尾,才視為有效(涵蓋 www./app./<workspace>. 等子網域,同時擋掉 evilnotion.com 這類同尾巴假冒網域)。
若 $ARGUMENTS 為空,使用 AskUserQuestion 請使用者提供 Notion URL。
若 URL 的 host 不在上述白名單內,提示使用者確認。
不使用 WebFetch / Playwright MCP(見全域規則 webfetch-blocklist.md:Notion 為 100% client-side rendering,且 MCP 每次操作注入 ~58KB snapshot)。
所有 playwright-cli 指令使用 session -s=notion 和 persistent profile --profile ~/.playwright-cli/notion-profile。
引號規則:
eval指令外層用 single-quote,內部 JS 用 double-quote,避免\"escape 導致 Playwright serialization 錯誤。
不穩定性止損(2026-07-10 實測): headless Notion session 會反覆自斷(browser 重啟成 in-memory、execution context destroyed、click ref 失效誤導航到 sidebar 其他頁)。守則:第一次 snapshot 就把 properties 與 comments 全部撈齊(accessibility tree 含
innerText拿不到的欄位與留言,一次 Read 完);後續互動展開(toggle、「Show N replies」)失敗重試上限 2 次,仍失敗就在輸出中標註缺口(例:「此留言下有 N 則收合回覆未擷取」)交給下游 HITL 補讀,不值得無限重試——缺口標註本身就是合格產出。
playwright-cli -s=notion open "<notion_url>" --profile ~/.playwright-cli/notion-profile
使用 eval 輪詢等待 Notion 內容 selector 出現:
playwright-cli -s=notion eval '() => new Promise((resolve, reject) => { const selectors = [".notion-page-content", ".notion-frame", "[data-block-id]", ".layout-content"]; const check = () => { for (const s of selectors) { if (document.querySelector(s)) return resolve(s); } setTimeout(check, 500); }; check(); setTimeout(() => reject("timeout: no Notion content found"), 15000); })'
若回傳非零 exit code 或 stderr 包含 error/reject 訊息,視為逾時,進入 Step 2c 檢查是否需要登入。
取得 snapshot 檢查頁面狀態(寫入執行時工作目錄下的 .playwright-cli/):
playwright-cli -s=notion snapshot
ls -t .playwright-cli/*.yml | head -1 # 找到最新 snapshot 檔案(於專案根目錄執行)
用 Read 工具讀取該 yml 檔案。判斷條件:snapshot 不含任何 data-block-id 相關內容,且包含 email、"Sign in"、"Log in"、"Continue with" 等字樣 → 視為登入頁面,使用 AskUserQuestion 提供選項(同 Step 0)。若已有 persistent profile 且 session 有效,直接繼續。
先展開所有 Toggle 區塊(Notion toggle 預設收合,子內容不在 DOM 中):
playwright-cli -s=notion eval '() => { const toggles = document.querySelectorAll(".notion-toggle-block > div[role=button]"); toggles.forEach(t => { if (t.getAttribute("aria-expanded") !== "true") t.click(); }); return toggles.length; }'
若有 toggle 被展開,sleep 1 等子內容載入。使用 eval 提取頁面文字內容(主要擷取方式,足以取得完整文字):
playwright-cli -s=notion eval '() => document.querySelector(".notion-page-content")?.innerText || "NO CONTENT"'
若需要更結構化的提取(標題 + 內容分離):
playwright-cli -s=notion eval '() => { const title = document.querySelector(".notion-page-block, .notion-collection_view-block h1, [data-root=true] h1")?.textContent?.trim() || ""; const content = document.querySelector(".notion-page-content")?.innerText || ""; return JSON.stringify({ title, content }); }'
若使用者的需求提及 Status、負責人、截止日期等屬性欄位,或頁面預期含有留言討論,則在完成 2d 後額外執行 Step 2f(
eval innerText無法取得 properties 和 comments,僅存在於 accessibility tree)。
在繼續前,對照 snapshot YAML 驗證擷取完整性:
data-block-id 的行數作為 block_countinnerText 回傳內容的行數(line_count)line_count < block_count * 0.5,視為擷取不完整,強制觸發 Step 2e 捲動若頁面內容需要捲動才能載入完全:
playwright-cli -s=notion eval '() => new Promise(resolve => { let lastHeight = document.body.scrollHeight; const distance = 500; const timer = setInterval(() => { window.scrollBy(0, distance); const newHeight = document.body.scrollHeight; if (newHeight === lastHeight) { clearInterval(timer); resolve(true); } lastHeight = newHeight; }, 300); setTimeout(() => { clearInterval(timer); resolve(true); }, 30000); })'
使用
scrollHeight穩定性檢查(連續兩次高度不變即停止),而非累計距離比較,避免 lazy-load 不斷擴展頁面導致無限捲動。
捲動完成後捲回頂部,重新擷取內容:
playwright-cli -s=notion eval '() => window.scrollTo(0, 0)'
若需求包含頁面屬性(如 Status、Assignee、Due Date)或留言討論,從 snapshot YAML 提取:
playwright-cli -s=notion snapshot
ls -t .playwright-cli/*.yml | head -1
用 Read 工具讀取,在 YAML 中搜尋:
table "Page properties" 區塊,提取各屬性的 key-valueComments 或 Discussion 區塊,提取留言內容與作者playwright-cli -s=notion close
清理 Notion UI 殘留文字,保留語意結構(標題層級、清單、程式碼區塊、表格),輸出:
# [頁面標題]
> 來源:[Notion URL]
> 擷取時間:[YYYY-MM-DD HH:MM]
---
[頁面內容,保留原始 Markdown 結構]
特殊內容依慣例轉換:表格/Database → Markdown table;Toggle → 展開後以 <details> 或縮排呈現;Callout → blockquote;程式碼區塊保留 ``` 與語言標記;嵌入標記為 [Embedded: URL];圖片用  或 [Image: description]。
對整理後的 Markdown 逐條驗證,任一 FAIL 則用 AskUserQuestion 詢問使用者:
| # | 驗證項目 | 結果 |
|---|---|---|
| 1 | 有標題(非空、非 "Untitled") | PASS / FAIL |
| 2 | 有段落文字(>50 字) | PASS / FAIL |
| 3 | (若 URL 含 ?v= database 參數)有表格資料 | PASS / FAIL / N/A |
| 4 | 內容長度與預期相符(Step 2d-verify 的 line_count / block_count 比值 ≥ 0.5) | PASS / FAIL |
全部 PASS(或 N/A)→ 進入 Step 5;任何 FAIL → 顯示失敗條目,詢問是否需要登入或改為手動貼上內容。
將 Step 3 整理好的結構化 Markdown 完整輸出至對話中,供後續 /design 讀取,再觸發:
Skill(skill="design", args="[SOURCE: /notion-plan] 根據上方 Notion 頁面的需求內容建立實作計畫")
[SOURCE: /notion-plan]為 traceability 標記,僅標示需求來源;/design不做任何 skip 處理(與/update → /pr的[PIPELINE]語意不同),而是從對話脈絡中讀取 Notion 內容,零修改/design。觸發後
/design的 Step 2a 會先派輕量分診 subagent(haiku)判定複雜度再決定走快速路徑或完整流程——測試回報/單一 bug 票通常落在快速路徑,不會為一張 P2 票展開完整儀式。
/notion-plan https://www.notion.com/workspace/Page-Title-abc123
/notion-plan https://www.notion.so/workspace/Page-Title-abc123 # 舊網域,自動轉址至 notion.com
/notion-plan https://workspace.notion.site/public-page-abc123