c4 是做什麼的?
C4 以三個縮放層級回答「這個系統是什麼、由什麼組成、誰呼叫誰」。底層是 visualize 引擎:一個 rataflow 畫布、每個層級一個描述區段、用於所有權的 containers 方塊。請閱讀 agents/.agents/skills/visualize/SKILL.md 以了解渲染器本身 — 此技能僅涵蓋 C4 新增的內容。
C4 新增了三項 visualize 未提供的功能:
- 層級階梯。 L0 上下文,接著是 L1/L1b 容器,然後是 L2/L2b 元件。每個層級的存在都是為了引出下一個層級,而讀者所在的層級是從方塊本身可見的,無需查閱圖例。
- 事實收集。 C4 必須完整呈現誰呼叫什麼以及為什麼。在產生任何規格之前,scout 會讀取程式碼庫並產生一個有證據支援的元素與關係清單。
- 包含作為一種主張。 一個容器方塊容納其元件的自身部分,不包含其他任何東西。這是一個所有權主張,因此需要來源,並且必須經得起讀者根據程式碼檢查該方塊。
不要憑空發明任何元素、關係或邊界。如果 scout 無法引用它,就不要繪製它。
路由
| 提問 | 使用 |
|---|---|
| 真實程式碼庫中元件的 C4 層級 | 此技能 |
| 根據已有事實繪製一個關係圖 | visualize |
| 在聊天回覆中的圖表 | mermaid 工具 |
| 靜態 ANSI / PNG | mermaid 技能 |
| 架構散文頁面或簡報 | artifact 技能 |
/c4 <component> 或「給我 X 的 C4 視圖」是呼叫方式。此技能可在其從未見過的儲存庫中運作:scout 是其學習任何資訊的唯一方式,因此這裡不需要事先了解程式碼。
步驟 0 — 鎖定元件
在任何 scout 執行之前,請說明:
component: machine manager
repo root: /Users/aviral/modal
anchor: machine_manager/ (一個套件,一個可部署單元)
- Component 是讀者可以在程式碼中指向的一個東西:一項服務、一個套件、一個可部署單元。如果提問命名了一個跨越多個可部署單元的子系統,請選擇該可部署單元並說明它將哪些鄰居視為外部系統。
- Repo root 是 scout 開始的地方。確認 checkout 存在;不要假定一個路徑。
- Anchor 是表明該元件為一體的最強單一證據(套件 manifest、Helm chart、Terraform 模組、proto 服務、
main.go)。如果你無法指出一個,則該元件很可能是兩個元件 — 請詢問人類,不要猜測。
最多問一個澄清問題(元件邊界是唯一值得問的)。否則自行決定並記錄。
步驟 1 — 啟動 scout
prompts/ 中有四個提示;每個都是一個完整的子代理任務。將它們作為 subagent 呼叫啟動,使用 agent: "scout"(唯讀偵查 — scout 不得編輯儲存庫),四個提示在一次回合中全部啟動以便並行執行,cwd: 為步驟 0 中解析出的儲存庫根目錄,並將元件名稱替換為 <component>:
| Scout | 提示 | 回傳 |
|---|---|---|
| 範圍 | prompts/scope.md | 元素清單:id、一句話角色、進入點、可部署單元、儲存、外部服務、角色、檔案路徑 |
| 關係 | prompts/relationships.md | from → to : verb + transport 行,每行附帶 file:line |
| 邊界 | prompts/boundary.md | 成員 vs 外部 + 證明每個成員資格的模組/部署邊界 |
| 層級 | prompts/levels.md | 每個元素的層級分配,以及哪些層級必須拆分為 L1/L1b (L2/L2b) |
每個 scout 都會回傳帶有 file:line 引用的證據。沒有這個引用的行是謠言;將其丟棄或要求該 scout 重新提供來源。
從儲存庫根目錄啟動 scout — 在那裡執行工作階段(或使 cwd: 與工作階段所在的目錄相同)。cwd 與產生它的工作階段不同的 scout 可能會在其程序啟動前死亡,而失敗訊息會顯示為「其窗格中未出現 pi 程序」。
不要輪詢子代理。結果會自行到達;當全部四個都返回時繼續。如果其中一個失敗,請說明是哪一個,並在生成記錄中重試或記錄此缺口 — 切勿憑記憶填補。
步驟 2 — 整合成一個總帳
將四個回傳結果合併到生成記錄中的三個表格中。這是整個事實庫;規格可能不包含任何不在這裡的內容。
elements: id | label | role | class (actor|external|member|store) | evidence
relations: id | from → to | verb + transport | level | evidence
boundary: id | inside/outside | justifying boundary | evidence
- 衝突通過引用更強的來源解決(manifest 或部署 chart 勝過註解;呼叫站點勝過文件字串),並且失敗的主張會被記錄下來,而不是刪除。
- 未解決的衝突和沒有倖存來源的關係會被記錄為開放問題。沉默是缺陷;可見的疑問則不是。
- 每個元素保留一個 id,並跨層級重用,因此追蹤
q → reg的讀者在 L1 和 L2 看到的是相同的兩個方塊。
步驟 3 — 要繪製什麼(優先排序)
C4 視圖是關於重要性的判斷,而不是呼叫圖的傾倒。總帳包含 scout 找到的每個關係;圖表包含讀者需要的那些關係,並明確說明它省略了什麼。
當一個關係至少滿足以下其中一項時,它就獲得一席之地:
| id | 測試 | 範例 |
|---|---|---|
| I1 | 它跨越元件邊界(成員 ↔ 外部,外部 ↔ 外部) | webapi → Latitude API,machines → sshx.io |
| I2 | 它是來源明確指出的主要請求、控制或資料路徑(佈建、心跳、稽核、調和、啟動) | control plane → private gRPC,River queue → workers |
| I3 | 它攜帶讀者需要的協定或限定詞:RPC 動詞、傳輸、埠、儲存桶、間隔、逾時 | register + heartbeat every 1 min,gcore sync every 1 min |
| I4 | 它解釋了讀者無法從方塊推斷出的資料儲存或角色 | store → Postgres,ops + mmctl → webapi |
| I5 | 它是必須保持可計數的冗餘或並行路徑中的一條 | machines → boot 和 boot → machines;兩個獨立的拉取 |
丟棄類別 — 一個關係僅在符合以下其中一項時才從圖表中移除:
| id | 類別 | 說明 |
|---|---|---|
| C1 | 內部細節 | 完全在一個容器內部,不增加邊界、協定或角色資訊(當儲存的寫入者已經繪製時,worker → store 的逐查詢行) |
| C2 | 重複呼叫站點 | 與已繪製的關係相同的躍點,僅在作業類型或參數上不同,而已繪製的標籤已包含這些資訊 |
| C3 | 輔助 | 一個唯一工作是重新進入同一容器的元素(兩個已繪製方塊之間的客戶端包裝器) |
| C4 | 冗餘途徑 | 一條路徑的進一步並行分支,其可計數性讀者不需要(來自同一儲存桶、相同傳輸的第二個成果) |
保持判斷誠實的規則:
- 一個箭頭可以攜帶多個呼叫站點,只要標籤包含它們的動詞(
create / terminate / repair)。這是 C2 摺疊,而不是刪除。 - 邊界跨越贏得平局(I1 優先於 I3,I3 優先於 I2)。為了容納內部躍點而丟棄外部躍點的圖表已經顛倒了自己的優先級。
- 有疑問時,就繪製它,並讓層級的描述說明它為什麼存在。疑問不是丟棄的理由;
C1–C4才是。 - 切勿靜默丟棄。 總帳中的每一行最終都是以下之一:已繪製、
摺疊到 <已繪製的關係>(並以 C2 證明摺疊合理),或已省略 — C1|C2|C3|C4附帶一行說明原因。覆蓋圖(步驟 7)會說明四個計數:已繪製、已摺疊、按類別省略、未說明。 - 範圍縮減是不同的東西,需要呼叫者的話語。「僅控制平面視圖」或「最多 20 個關係」是範圍要求:將其記錄為基礎(
basis: caller scope, N relations),與計數後的總帳一起。優先排序是預設行為;子集是呼叫者做出的決定,而不是生成器推斷的決定。
步驟 4 — 層級階梯
目標形狀是五個區段,從上到下:
L0 · 系統上下文 元件的一個節點 + 其鄰居
L1 · 元件 元件打開一次,容器包含其部分
L1b · <第二側> 相同深度,系統的另一側
L2 · 內部 — <切片 A> 成員之間的關係,容器包含它們
L2b · 內部 — <切片 B> 相同深度,另一個切片
這就是階梯:一個五區段的畫布是交付物。更多的區段是缺陷,除非滿足下面的拆分紀律(附帶數字)。
每個層級僅在其上一個層級存在後才繪製,並在繼續之前為每個層級提供其描述。
| 層級 | 繪製內容 | 方塊行為 |
|---|---|---|
| L0 系統上下文 | 元件作為一個普通節點,加上周圍的每個角色和外部系統,以及它們之間的粗略箭頭 | 無容器、無 focus、無雙框線 — 重點是周圍的世界,因此元件看起來像任何其他方塊 |
| L1 容器 | 元件打開一層:其自身的可部署/執行階段單元在一個容器內;L0 的外部保持在外部 | 成員上的容器方塊 |
| L1b 側視圖 | 當一個 L1 確實無法容納流程時(集群端、資料平面、批次路徑)的可選第二個切片 — 經測量,絕非新主題 | 容器,規則相同 |
| L2 元件 | 一個容器內部的關係 — L1 的成員,現在互相呼叫 | 在它們周圍的容器方塊 |
| L2b | 當一個 L2 無法路由其關係,或兩個故事需要不同層次時,相同深度的可選第二個切片 | 容器,規則相同 |
不可協商的層級規則:
- L0 是作為一個普通節點的元件。 整個元件一個方塊,其普通邊框,加上周圍的角色和外部系統。不是其部分、其監聽器、其表格 — 這些是下一個層級。如果 L0 有超過一個屬於元件內部的節點,則它不是上下文視圖。L0 上的包含會聲稱讀者尚未看到的內部細節,而
focus會指向一個尚不存在的層級。 - L1/L1b 打開 L0 的方塊。 每個成員都坐在容器內部;每個在 L0 是外部的元素都坐在它外部。無法在方塊邊界框之外繪製的成員會獲得自己的容器條目(請參閱連續性規則) — 絕非湊合的。
- L2/L2b 保持在一個方塊內部。 L2 關係的兩個端點都是容器成員。如果關係離開方塊,則它屬於 L1/L1b。
- 一個層級描述自身。 標題是簡短的(
L0 · 系統上下文);描述說明方塊內部是什麼、外部是什麼,以及它與相鄰層級的關係。目標是 2–3 行。 - 動畫不是 C4 屬性。 層級 0–1b 是靜態的(
dots: 0)。其關係是即時流程的內部層級可以每條路線攜帶恰好一個點(flow: true, dots: 1);記錄此選擇。切勿為裝飾階梯而動畫化外部箭頭。
拆分紀律 — 一個層級是一個深度,而不是一個主題
C4 層級以一個縮放回答一個問題。相同深度的兩個層級的存在僅是因為一個區段無法容納內容;一個新的主題不是添加區段的理由。
- 切勿添加 L1c、L1d、L1e 或第五個側。 階梯有三個深度(上下文、容器、元件),並且在第一個深度以下最多有兩個切片。一個每個子系統或每次提到就增長一個切片的畫布是一個主題列表,戴著層級頭銜。
- 第二個切片必須命名其測量標準:
--check拒絕的路線、它所報告的共享通道,或發生衝突的層次(兩個外部端點,沒有共同的外部)。「感覺很擠」不是一個。 - 相同深度的切片共享方塊、標籤和 id。 L1 和 L1b 繪製相同的元件,使用相同的成員 id;L2 和 L2b 繪製相同的成員。只有邊集合和層次不同,並且每個描述說明它是哪個切片。
- 一個切片命名為
b(l1b、l2b);切勿發明一個深度。 - 不繪製 L2 以外的深度。 如果元件內部仍然分解,請在記錄中說明並停止:程式碼類別和函數不是讀者要求的 C4 層級。階梯在要求結束的地方結束。
- 總帳中所有未在階梯中繪製的內容都是一個範圍決定,需記錄下來(步驟 6),不是靜默刪除,也不是一個新的區段。
步驟 5 — 規格機制
一個畫布、一個閱讀方向、每個層級一個區段:
{
"direction": "lr",
"theme": "gruvbox",
"diagrams": [
{
"id": "l0",
"title": "L0 · 系統上下文",
"description": "系統上下文:管理器是一個方塊。...",
"nodes": [ ... ],
"edges": [ ... ]
},
{
"id": "l1",
"title": "L1 · 管理器",
"description": "L0 的方塊打開一層:...",
"containers": [ { "label": "Machine manager", "members": ["api", "q", "db"] } ],
"layers": [ ["actor"], ["api", "q"], ["db"], ["prov"] ],
"nodes": [ ... ],
"edges": [ ... ]
}
]
}
direction: "lr"一次,在畫布上。切勿有每個圖表的覆蓋:每個區段都重新定向的讀者已經失去了階梯。- 五個區段。
l0、l1、l1b、l2、l2b,按此順序。第六個區段需要記錄步驟 3 的測量;一個有十個或二十個區段的畫布是一個主題列表,而不是一個階梯 — 將其摺疊回三個深度各兩個切片。 containers是一個每個圖表的列表,包含{label, members}。方塊是一個真實的雙邊框矩形,圍繞成員生長,標籤嵌入其頂部邊緣。每個圖表允許多個方塊。- 成員 id 必須存在於該圖表的
nodes中。 命名了不存在節點的成員 id 會被解析器靜默丟棄 — 然後方塊圍繞比你聲稱的更少的節點繪製,而--check不會發出警告。對照你宣告的成員來計數已繪製的方塊。 - 連續性規則。 一個容器是一個矩形
…
[翻譯截斷]