Close the 會議記錄 → 管控表 loop for one meeting: parse a [會議記錄] Doc's four tables (進度更新 · 提醒與阻礙 · 決議 · Action Items), then append-or-patch three 管控表 tabs — Action Items into 專案管理總表, 決議 影響 ≠ 無 into Change & Decision Log, Blocker 阻礙 unresolved ≥ 7 days into Risk Register — and print a diff of what moved. Trigger on /project-minutes-sync or 「同步會議記錄」「把會議記錄同步到管控表」「會議決議同步」「Action Items 進管控表」「阻礙開成 Risk」「sync the minutes」「把這場會的決議寫進 Change Log」. NOT project-note-specialist (3.08), which reshapes raw notes i...
Scanned 9/19/2026
Install to Claude Code
npx -y skills add peter-tu-zynkr/zynkr-skill-builder --skill project-minutes-sync --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Project Minutes Sync?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/peter-tu-zynkr-project-minutes-sync)More formats (shields.io, HTML) on the badges page.
---
name: project-minutes-sync
category: operations
project: project-minutes-sync
platform: claude
status: WIP
author: Peter Tu
sheetId: "3.21"
description: >-
Close the 會議記錄 → 管控表 loop for one meeting: parse a [會議記錄] Doc's four tables
(進度更新 · 提醒與阻礙 · 決議 · Action Items), then append-or-patch three 管控表 tabs —
Action Items into 專案管理總表, 決議 影響 ≠ 無 into Change & Decision Log, Blocker 阻礙
unresolved ≥ 7 days into Risk Register — and print a diff of what moved. Trigger on
/project-minutes-sync or 「同步會議記錄」「把會議記錄同步到管控表」「會議決議同步」「Action Items
進管控表」「阻礙開成 Risk」「sync the minutes」「把這場會的決議寫進 Change Log」. NOT
project-note-specialist (3.08), which reshapes raw notes into the 4-section weekly update
and touches no Sheet; NOT project-status-update (3.09), which READS the tabs this skill
feeds and drafts the weekly mail; NOT project-init (3.20), which creates a project.
input: "A [會議記錄] Doc (URL or id) or a project slug that resolves via pm.json; the tracker Sheet id always comes from the adapter."
process: "知識來源 + pm.json check → parse the Doc's four tables per-table → detect the 管控表 version with pm-schema.py → Action Items append-or-patch tab 1 → 決議 → Change & Decision Log → 阻礙 → Risk Register → VALUES-ONLY write-back → diff report."
output: "Three 管控表 tabs updated by value only, the Doc's 已同步 checkboxes ticked on explicit go-ahead, and a chat diff report — appended · patched · skipped · unparsed · needs a human."
synergy: [project-status-update, project-note-specialist, project-init, admin-meeting-prep]
house-style: bound
---
# project-minutes-sync
```bash
npx skills add https://github.com/peter-tu-zynkr/zynkr-skill-builder --skill project-minutes-sync
```
會議記錄模板早就寫死兩條 MANDATORY 同步:一筆「決議」若影響範疇/時程/預算,必須同步到管控表的 Change & Decision Log;一筆「阻礙」若一週內無法自行解除,必須開一筆 Risk Register 並填 Owner 與狀態。這兩件事今天全靠手動,於是週報的 RECENT DECISIONS 讀的是一張沒人填的表。這個技能就是把那一段補起來——讀一份 Doc、寫三個分頁、回報一份 diff。它刻意很薄:不判定影響範疇、不代簽核准、不猜機率與衝擊、不寄任何信;判斷留給人,這裡只負責把已經寫下來的東西搬到它該在的表上,並把搬不動的部分點名。
---
## 這個技能與鄰居的分工
- **project-note-specialist(3.08)** — 把凌亂的筆記/逐字稿整理成四段週報格式;不碰任何 Sheet。它處理「文字長什麼樣」,本技能處理「這些文字該進哪張表」
- **project-status-update(3.09)** — 讀管控表出週報草稿。它的 RECENT DECISIONS 從 Change & Decision Log 讀,本技能就是餵那張表的人;週報相關的觸發詞一律歸它
- **project-init(3.20)** — 開案:複製模板、建資料夾、建管控表。本技能只在案子已經存在、也已經開過會之後才跑
- **admin-meeting-prep(3.03)** — 會前包:排程掃行事曆與信箱,會議前把行動提醒與 briefing 推到 Google Chat。本技能是同一場會的會後那一段
- **admin-meeting-note(3.04)** — `admin-meeting-prep` 底下的 agent(`agents/admin-meeting-note.md`),把會後的原始筆記/逐字稿整理成四段更新。它整理文字、不碰任何 Sheet,也不解析 `[會議記錄]` 的四張表;和 3.03 是兩個不同的東西,別把 id 對調
## 固定事實(先讀,別在這裡重述規則)
- `./references/pm-knowledge-pack.md` — §2 五個軸與三條裁決 · §3 管控表 v2 的 14 欄與強制版本偵測 · §4 編號與日期 · §5 Gate 與 Drop 留痕 · §6 升級與同步的兩條強制規則 · §9 讀這份知識包的技能四條鐵律
- `./references/pm-sources.md` — 8 份 PMO 模板 ID(§1)· `~/.config/zynkr/pm.json` adapter 契約與 Step 0 驗證順序(§2)· instance ID 只住 pm.json 這條規則(§2.3)
- `./references/pm-sheet-schema.json` — 分頁 → 標頭字串;本技能會寫的兩張表在這裡:`Risk Register`(10 欄)· `Change & Decision Log`(9 欄)
- `./references/pm-status-crosswalk.json` — 五個軸、各表面的值對照、`rejected_values`(`取消`/`暫停`)、`% = done / (total − dropped)`
- `./scripts/pm-schema.py` — 標頭與值的驗證 CLI(python3 標準庫,`--help` 可看退場碼)
**這五份都是技能自帶的,路徑一律以技能資料夾為根。** 安裝指令 只裝這一個資料夾;repo 的 `docs/pm-shared/` 與根目錄 `scripts/` 在安裝後的環境裡並不存在,指過去只會拿到 `No such file`。`scripts/check-pm-refs.sh`(住在 repo,給維護者跑)保證這五份與 `docs/pm-shared/` 逐位元組相同。呼叫 CLI 時把 seed 明給——`--schema ./references/pm-sheet-schema.json` · `--crosswalk ./references/pm-status-crosswalk.json`——因為 CLI 的內建預設值指向 repo 版面。
知識來源:references/pm-knowledge-pack.md · v1 · sha256 15640433fbee
Google 帳號、時區、週起始日與門檻值全部從 `pm.json` 讀(`pm-sources.md` §2)。本檔沒有、也不得出現任何專案的 Sheet/Doc/資料夾 ID。
---
## Step 0 — 知識來源與設定檢查
1. **知識來源**:算出手上這份知識包的 sha256 前 12 碼,和上面那行宣告比對。
```bash
shasum -a 256 ./references/pm-knowledge-pack.md | cut -c1-12
```
不一致就**停**,回報兩個值,並指向 `scripts/check-pm-refs.sh --sync`。宣告過期代表這份技能是照舊規則寫的,照跑等於用舊規則寫別人的表——停下來永遠比較便宜。
2. **設定**:讀 `~/.config/zynkr/pm.json`(可用環境變數 `ZYNKR_PM_CONFIG` 覆寫),依 `pm-sources.md` §2 的順序驗證:檔案存在 → 指定的 slug 在 `projects` 底下 → 它的 `engagement_type` 是 `engagement_types` 的 key → 這次要用到的 `tracker_sheet_id` 與 `minutes_doc_id` 非空、也不是 `<...>` 佔位。任何一關失敗就印出鍵路徑並停,例如 `config: projects.<slug>.tracker_sheet_id unset`。
3. **不猜 ID**:不得回頭用本檔的字面值、不得用 Drive 標題搜出「看起來對的那一份」、不得沿用上一次跑到的 ID。寫錯一張表,等於把一場會的決議寫進別人的專案。
## Step 1 — 輸入:一場會議、一個專案
- 接受兩種輸入:**(a)** 一份 `[會議記錄]` Doc 的 URL 或 ID;**(b)** 一個專案 slug,經 `projects.<slug>.minutes_doc_id` 解析成同一份 Doc。
- **管控表一律從 adapter 解析**:`projects.<slug>.tracker_sheet_id`。只給 Doc、沒給 slug 時,請使用者補上 slug——不要從 Doc 內文的連結反查 Sheet,那條路徑無法驗證。
- 一次只處理一場會議。多場會議=多次執行,避免同批次的編號與去重互相污染。
- 記下這場會議的日期(Doc 標頭),後面 Change & Decision Log 的 `日期` 與 Risk Register 的 `最後檢視日` 都用它。
## Step 2 — 讀 Doc,逐表解析
用 `get_doc_content` 或 `get_doc_as_markdown` 取內容,必要時以 `inspect_doc_structure` 對照表格結構。若頂層 body 讀出來是空的,改帶 `tab_id` 再讀一次(Docs tabs 的已知行為),不要當成「這份 Doc 是空的」。
要解析的四張表,其餘(討論摘要 · 下次會議 · 出席)一律不動:
| 表 | 讀出來要用在哪 |
|---|---|
| 進度更新(`狀態 On track/At risk/Delayed/Done`) | Step 7,只讀不寫 |
| 提醒與阻礙(`類型 Call-out/Blocker`、`已同步 Risk Register?`) | Step 6 |
| 決議(`影響 範疇/時程/預算/無`、`已同步 Change & Decision Log?`) | Step 5 |
| Action Items(`Owner|Due|對應管控表任務 no.|狀態`) | Step 4 |
規則:
- **以標頭字串定位欄位**,不以欄位順序;標頭找不到就當這張表解析失敗。
- **逐表隔離**:一張表解析失敗,另外三張照跑。報告要點名是哪一張、失敗在第幾列、什麼問題。
- **缺表要點名,不得當成空表**:找不到的表在報告寫「未找到(不視為空)」。「這場會沒有決議」和「決議表沒讀到」是兩件完全不同的事,混在一起會讓漏同步變成靜默成功。
- **日期缺年份不補**:知識包 §4 要求日期含年份;沒有年份的日期標 `(日期待確認)`,排除在所有日期運算外,列進報告。
## Step 3 — 偵測管控表版本(對映任何欄位之前)
1. 先讀表頭區塊而不是只讀第 1 列:`read_sheet_values(<tracker_sheet_id>, "專案管理總表!A1:N6")`。實際的表上,第 1 列常是核心目標、標頭落在第 3 列。**以第一個儲存格等於 `no.` 的那一列為標頭列**,並記住它的列號——資料列從它下面開始。找不到這樣的一列就停。
2. 把那一列丟給 CLI:
```bash
python3 ./scripts/pm-schema.py headers \
--tab 專案管理總表 \
--headers "no.,里程碑 Stage,…" \
--schema ./references/pm-sheet-schema.json
```
| 退場碼 | 意思 | 這次執行怎麼辦 |
|---|---|---|
| 0 | v2,14 欄 A–N | 用 v2 對映往下跑 |
| 2 | legacy v1,13 欄 A–M(沒有 `前置任務 Depends on`) | **回報後照跑**,改用 v1 對映(`K`=`Reference 連結`·`L`=`Note`·`M`=`DOD`) |
| 1 | 標頭不吻合任何一版 | **停**。印出 CLI 給的逐欄差異,不猜、不硬寫 |
| 3 | 跑不起來(找不到 seed、參數錯——最常見的是漏了 `--schema`) | 這不是判定,是安裝/參數問題:回報並停 |
3. **不要用人工比對代替 CLI。** CLI 與它要讀的兩份 seed 都隨技能一起安裝(`./scripts/pm-schema.py` · `./references/*.json`),所以「拿不到 CLI」不再是一種正常情況——那代表安裝壞了或參數給錯,是要修的事,不是要繞過的事。退場碼 3 一律回報並停。
4. **永遠不得寫死範圍**。`project-status-update` 曾寫死 `A1:M44`,在 v2 表上把 `前置任務` 當成 `Reference` 讀——那是這批變更要修掉的活 bug,不要在這裡複製一次。
## Step 4 — Action Items → tab 1 專案管理總表
先把 tab 1 讀進來(標頭列以下全部),建立 `no.` → 列號的索引,再逐筆處理 Action Items:
- **有 `對應管控表任務 no.`,且該 no. 存在** → **PATCH**:只寫 `Owner` · `End (YYYY/M/D)` · `Status` 三欄,其餘一字不動。`任務描述`、`DOD`、`Note`、`前置任務`、`Reference` 都不覆蓋——會議記錄寫的是這一週的變化,不是這一列的全文。三欄裡沒給的那幾欄維持原值,不要用空字串洗掉。
- **有 no.,但 tab 1 找不到** → **衝突**:不寫、不新增、不改號,列進報告的「跳過」並附上原值。指到不存在的 no. 可能是打錯,也可能是有人刪過列,兩種都得由人看。
- **沒有 no.** → **APPEND**:依 `里程碑 Stage` 對到階段,取該階段現有最大的 `X.Y` +1,`Status` 一律寫 `Not started`。同一批次內自行遞增,避免兩筆撞同一個號。判斷不出屬於哪個階段時不要硬塞,列進「需人決定」。
- **永遠不得發明 `no.`**,也不得為了讓順序好看而重排既有編號——重排會讓所有 `前置任務` 參照失效(知識包 §4)。
- Action Item 的 `狀態` 只允許 lifecycle 表面四值 `Not started / WIP / Done / Drop`。出現 `取消`、`暫停` 之類的值,依 crosswalk 的 `rejected_values` 回報建議值(`取消` → `Drop`/`放棄`;`暫停` 是專案層級的狀態,任務要寫成 `WIP` + Note 或 `Drop` + 一筆 Change & Decision Log),**不自行換算**。要驗一批值:
```bash
python3 ./scripts/pm-schema.py values \
--values "Done,WIP" --axis lifecycle_sheet \
--crosswalk ./references/pm-status-crosswalk.json
```
- 一列被改成 `Drop`,同一次動作必須在 Change & Decision Log 留一筆(知識包 §5);會議記錄裡沒有對應決議時,把它列進「需人決定」,不要無聲地 Drop。
## Step 5 — 決議 → Change & Decision Log
- **篩選**:只取 `影響` 不是 `無` 的列(影響範疇/時程/預算)。`影響` 欄空白代表還沒判定,列進「需人決定」——判定影響範疇是人的工作,不是這個技能的(知識包 §6)。
- **一列一筆**,九欄依 `pm-sheet-schema.json` 的順序:`日期` · `類型 變更/決策` · `內容` · `原因` · `影響 範疇/時程/預算/無` · `提出人` · `核准人` · `狀態 提案/核准/駁回` · `關聯任務 no.`。
- **`狀態` 一律寫 `提案`**。這是 decision 軸,不是 lifecycle 軸——這欄永遠不會出現 `WIP` 或 `Done`。核准是人在 Gate 上做的動作,技能不代簽(鐵律 4)。
- `核准人` 沒有就留空,不要填提出人充數。`關聯任務 no.` 只在會議記錄寫了、且該 no. 存在時才填。
- **去重**:同一 `日期` + 同一 `內容` 已經在表上就跳過,列進報告的 skipped-duplicate。同一場會被跑第二次不應該長出第二筆。
- 這一步存在的理由寫在知識包 §6:週報的 RECENT DECISIONS 從這張表讀,不從會議記錄讀。
## Step 6 — 阻礙 → Risk Register
- **升級條件三個同時成立**:`類型` = `Blocker` · 仍未解除 · 距首次出現已達門檻天數。門檻讀 `defaults.health_thresholds.blocker_stale_days`(預設 7),對應知識包 §6 的「一週內無法自行解除」與 §2.2 at_risk 用的是同一條線。
- **「首次出現」怎麼算**:以這筆阻礙在會議記錄中最早出現的那場會議日期為準。只讀得到一場會議時,就用該場日期計算,並在報告寫明依據是哪一天——不要用「感覺拖很久了」升級。
- 欄位:`風險描述`(用原文,不改寫)· `類別`(會議記錄寫了才填)· `Owner`(**必填**)· `狀態 Open/Monitoring/Closed` = `Open`(**必填**)· `最後檢視日` = 這場會議日期。
- **`機率 1-3` · `衝擊 1-3` · `分數` 一律留白給人**。分數是機率×衝擊,直接決定要不要升級;猜一個數字等於替人做了升級決策。
- `緩解措施` · `應變計畫` 只在會議記錄原文寫了才填,沒有就留白。
- **Owner 缺就不寫**:把該筆列進「需人決定」。Owner 與狀態是這條規則的必填項,開一筆沒有 Owner 的風險等於沒開。
- `Call-out` 類型不升級。未達門檻天數的 Blocker 也不升級,但要在報告列成「觀察中(第 N 天)」,下次會議它就到期了。
## Step 7 — 進度更新只讀,永遠不寫進 Status
這一步單獨成段,因為它就是五個軸那條裁決存在的原因,也是這個技能最容易犯的錯。
- 進度更新那欄的 `On track / At risk / Delayed` 屬 **health 軸**,是一次讀數;`Done` 是 crosswalk 明寫的跨軸例外(`axes.health.cross_axis`),解析成 lifecycle 的 `done`。
- **永遠不得把 health 讀數寫進 tab 1 的 `Status`**;反向也一樣——`Status` 沒有日期不足以單獨變成一顆 RAG 燈。
- 這一步只做兩件事:讀出來、印進報告,並和知識包 §2.2 的推導比對——🔴 `delayed` = `End < today` 且 lifecycle ≠ `done`;🟡 `at_risk` =(`End ≤ today + N` 且 lifecycle = `not_started`)或有一筆未解除、已超過門檻天數的阻礙;🟢 `on_track` = 其餘。那個 `N` 讀 `defaults.health_thresholds.at_risk_within_days`(預設 3),和 Step 6 的 `blocker_stale_days` 一樣是 adapter data——三個門檻是同一組可調數字,**不要把 3 寫死在這裡**,寫死等於在同一份檔案裡一邊讀設定一邊無視設定。
- 人填的讀數和推導不一致時,**兩個都報,一個都不改**。不一致本身就是要給人看的訊號。
## Step 8 — 寫回:只寫值,Doc 打勾要先問
**順序**:tab 1(Step 4)→ Change & Decision Log(Step 5)→ Risk Register(Step 6)。每張表一次寫入,寫完再寫下一張。
- 用 `mcp__google-workspace__modify_sheet_values`,`value_input_option="RAW"`——`2026/9/2` 這種字串照原樣落地,不被試算表重新解讀成別的格式。
- **append** 要先讀出該分頁目前的實際列數,寫在最後一列的下一列;不要用估的行號,也不要靠「應該有空白列」。**patch** 只寫那三個儲存格所在的範圍。
- **VALUES ONLY**:不重新轉檔、不改格式、不動欄寬、不排序、不插入或刪除列。這是一張正在被人使用的表,任何結構性動作都會弄壞別人的檢視與公式。
- 不碰 `所有檔案` · `Comms Plan` · `Budget` · `Stakeholders & RACI` · `Prerequisite Checklist`——本技能只寫三張表。
- **Doc 的兩個打勾欄要先取得明確同意**:`已同步 Risk Register?` 與 `已同步 Change & Decision Log?` 在會議記錄 Doc 上。把「要打勾的是哪幾列」列出來問使用者,得到明確同意才用 `batch_update_doc` 只改那幾格的文字。沒有同意就停在這裡:三張表的寫入照樣算數,報告寫明「Doc 未打勾」。寫別人正在編輯的 Doc 從來不是預設動作。
- 全程不寄信、不通知、不發任何訊息。
## Step 9 — 回報 diff
固定形狀,印在對話裡:
```
會議記錄同步 · <slug> · 會議日期 <YYYY/M/D>
知識來源 v<N> · sha256 <12 碼> · 管控表 <v2|legacy v1>(pm-schema.py 判定)
新增
專案管理總表 <n> 列 ← Action Items
Change & Decision Log <n> 列 ← 決議(影響 ≠ 無)
Risk Register <n> 列 ← 阻礙(Blocker,已達 <N> 天)
更新(只動 Owner/End/Status)
<no.> <任務> Owner <舊>→<新> · End <舊>→<新> · Status <舊>→<新>
跳過
<項目> — <no. 不存在/重複/缺 Owner/值不在四值內>
解析失敗
<表名> — <第幾列、什麼問題>/未找到(不視為空)
health 讀數(只讀不寫)
<項目> 人填 <值> · 推導 <值> · <一致|不一致>
需人決定
- <影響欄空白的決議/對不到階段的 Action Item/缺 Owner 的阻礙/沒有決議紀錄的 Drop>
Doc 打勾 <已打勾 n 列|未打勾(未取得確認)>
```
沒有任何東西被寄出。報告只印在對話裡,讓人決定下一步。
---
## 硬規則
1. **只回報,永不寄送**。這個技能不產生任何郵件、訊息或通知。
2. **讀不到就回報,永不猜**。缺表點名、缺年份標記、標頭不吻合就停、`前置任務` 指向不存在的 `no.` 一律回報。
3. **Sheet 回寫只寫值**。不轉檔、不改格式、不動欄寬、不重排。
4. **永不發明 `no.`**。新增列依知識包 §4 遞增;衝突回報,不自行解決。
5. **跨軸不轉換**。health 讀數不進 `Status`;decision 的 `狀態` 不寫 lifecycle 的字;risk 的 `狀態` 不寫 decision 的字。
6. **不代人做判斷**。不判定影響範疇、不代簽核准人、不猜機率與衝擊、不替人決定該不該 Drop。
7. **ID 只從 `pm.json`**。本檔不含任何專案 ID,執行時也不從 Drive 標題猜。
8. **一次一場會議、一個專案**。
## House style
Writing style is **not owned by this file**. The house voice lives in two Google Docs under
`[@] 寫作指南` (`12DBdFz3SK22ie9im_ThFMI7IBRXsTZsV`), read at runtime:
- 《[2.0] Zynkr 通用風格指南 House Voice》 `10bOIQwRm9Pxwgct4hlwCwK_B4Pipai1HqBPZKzyRHSE` —
the universal core, plus the addendum for this surface
- 《[3.2] 禁用詞清單 Forbidden Words》 `1N5sHLP4qzmmhpCGsi6KElxi1z0MFe4QZ0Q_35T10Uyg`
Read both before producing client- or reader-facing text, and scan the draft against 《[3.2]》
before handing it over. If Drive is unreachable, say so in the output rather than proceeding
unchecked. Never re-implement either list inside this file.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!