Community程式設計與開發github.com

begin / 開始探索

在面對不熟悉或印象模糊的程式碼庫時使用,或當使用者說「了解這個程式碼庫」、「快速上手」、「從何開始」、「這是什麼 repo」、「/begin」或詢問上次進度時。透過匯入圖、Git 變動頻率及近期 PR 推導出重要與複雜部分,將每個熱點檔案連結到其服務的使用者面向,並撰寫 BEGIN.md — 一份隨著每次推送誠實更新的程式碼知識圖譜。

開始探索 是什麼?

`begin` 是一種 AI 助手技能,旨在解決一個常見問題:AI 代理在陌生的程式碼庫中隨意搜尋關鍵詞,讀取少數幾個巧合匹配的檔案,然後給出一個僅描述系統 4% 的自信架構摘要。 它透過以下方式取代猜測:1) **測量而非回憶** — 使用 PageRank 分析真實的匯入圖(import graph)來決定重要性,透過決策點計數衡量複雜度,並從 Git 變更記錄和合併請求(PRs)中提取關注焦點。2) **每個主張都有錨點** — 在產生的 `BEGIN.md` 中,每個陳述都引用具體的 `檔案:行程式碼`、提交(commit)或 PR 編號,消滅無根據的猜測。3) **雙層結構** — `.begin/` 目錄包含可自動重新生成的機器層輸出(已加入 `.gitignore`),而 `BEGIN.md` 則是人工撰寫的說明文件,並標記衍生其內容的提交識別碼。4) **誠實的代理解釋** — 清楚說明各項測量指標(如 `complexityProxy` 是決策點計數,並非語法解析),並在測量結果降級時(例如淺層複製、無變更記錄、無法解析的語言)明確發出警告。 支援所有能執行 shell 腳本和 Node.js 的程式碼庫,尤其是 JavaScript/TypeScript 和 Python 專案(針對這兩種語言有完整的靜態解析),而 Go、Rust 等語言則回報有限的圖形資訊並發出警告。它提供清晰的五步驟操作流程:先執行 `recon.sh` 取得情境資訊,再執行 `scan.mjs` 取得結構化地圖,依據測量結果選擇性讀取檔案,在撰寫報告前進行驗證,最後撰寫並維護 `BEGIN.md`。它還包含一個 Git 鉤子(post-commit hook),會自動重新生成機器層並報告哪些章節已過時,確保文件在每次交付後都能保持最新狀態。

相容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Manueldav2/begin/tree/main/plugins/begin/skills/begin

Installed? Explore more 程式設計與開發 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

開始探索 是做什麼的?

以一次性的方式,根據證據在程式碼庫中定位,無需漫無目的地瀏覽。

這個技能存在的目的是防止以下失敗:AI 代理開啟一個儲存庫,搜尋一個聽起來合理的詞,閱讀三個恰好匹配的檔案,然後給出一個自信的架構摘要,但只描述了系統的 4%。begin 用測量取代猜測,找出重要程式碼的位置,然後只讀取測量結果指向的內容。

合約

  1. 不回憶,一切皆推導。 重要性來自於真實匯入圖(import graph)的 PageRank 演算法;複雜度來自於計數決策點;焦點來自於 Git 和 PR 記錄。如果你無法指向一個 檔案:行程式碼 或一個提交,就不要說出來。
  2. 每個主張都有錨點。 BEGIN.md 中的每個陳述都引用 檔案:行程式碼、一個提交或一個 PR 編號。一個無錨點的句子就是猜測,而這個技能的存在就是為了消滅猜測。
  3. 雙層結構,其中一層是活的。 .begin/ 是機器輸出,可重新產生且會自我忽略。BEGIN.md 是你撰寫、提交,並標記其衍生來源提交的散文。一個 post-commit 鉤子會重新衍生機器層,並報告哪些散文章節已被程式碼超越。此技能從不編輯已追蹤的檔案 — .begin/ 自身帶有 .gitignore,因此不會觸動儲存庫的 .gitignore。
  4. 代理(Proxy)必須被明確命名。 complexityProxy 是決策點計數,不是語法解析。巢狀結構是透過縮排來測量的。請明確說明;不要將代理偽裝成事實。
  5. 降級的測量結果必須被宣告,絕不能默默使用。 掃描時若遇到淺層複製、無變更記錄視窗、遺失檔案、完全無法解析的語言,或解析失敗但可部分處理的語言,會印出 [!WARNING] 區塊。在閱讀表格之前,請先閱讀該區塊,並在 BEGIN.md 中重複其內容。 建立在破碎圖形上的排名看起來和好的排名一模一樣 — 這就是全部的危險所在。

執行指令

S=~/.claude/skills/begin/scripts

bash  $S/recon.sh      # 誰/什麼/何時:PR、你的提交、即時編輯、文件
node  $S/scan.mjs      # 結構:匯入圖、熱點、前端(surface)->引擎(engine)

兩者都會寫入 .begin/ 並印出摘要。在儲存庫的任何位置執行 — 掃描會自動定位到儲存庫根目錄。recon.sh 在沒有 gh、沒有網路和沒有遠端的情況下也能優雅地降級,但它需要 node(編輯功能是強制的)。量測到的熱快取時間:259 個檔案 0.24 秒 · 3,384 個檔案 1.9 秒 · 2,809 個檔案 1.9 秒 · 1,819 個檔案 2.5 秒 · 1,397 個檔案 3.5 秒。檔案數量無法預測時間;內容才會。

有用的旗標:

  • --since "90 days ago" — 變更記錄視窗(兩個腳本預設為 90 天)。
  • --top 40 — 列印多少個熱點(預設為 25)。
  • --author "..." — 一個正規表達式。你很少需要它:它預設為儲存庫的 user.name,而 recon.sh 會回退到儲存庫中最活躍的作者,並在你沒有提交時告知。這在你剛克隆的儲存庫中是正常情況。
  • --exclude 'examples/**,site/**' — 將供應商(vendored)目錄和文件網站排除在前端(surface)計數之外。模式在兩端固定,並且會印出被移除的檔案數量,因為靜默的排除會在後續表現為遺失的邊緣(edge)。
  • --root DIR — 掃描不同的儲存庫。

操作順序 — 請嚴格遵守

順序錯誤是導致 AI 代理最終讀錯檔案的原因。

1. 先進行偵查(Recon),再分析結構

先執行 recon.sh。它會回答「這個人一直在做什麼?」— 未提交的編輯、分支與主分支的提交、最近約 20 個已合併的 PR(包含它們的內文),以及每個 PR 更改了什麼。這就是關注焦點的先驗資訊。完整閱讀 .begin/recon.md;它很短。

未提交的差異(diff)通常是儲存庫中最有資訊價值的東西 — 它是使用者當前持有的問題。偵查(Recon)會標記三件事:當工作目錄乾淨時,它會明確說明(而不是省略該章節讓你去尋找);當差異僅包含鎖定檔案和建置輸出時,它會告訴你不要在第一輪閱讀中浪費時間;當你的簽出(checkout)落後於 origin 時,它會告知落後了多少個提交,並列出近期 PR 中不在你工作目錄中的檔案名稱。

最後一點是前提條件,而非附帶條件。 如果偵查報告你落後了,則下面的步驟 3.2 是不安全的:PR 檔案列表描述的是你尚未擁有的程式碼。請先執行 git pull,或者跳過 PR 閱讀步驟,並在 BEGIN.md 中說明你跳過了。

2. 再分析結構

執行 scan.mjs 並閱讀 .begin/scan.md,從任何 [!WARNING] 區塊開始。接著,你將獲得基於測量而非假設的以下資訊:

  • 前端(Surfaces) — 人類或呼叫者實際觸碰系統的每個地方,按種類分組(web-page、ui-component、http-route、cli-command、mcp-tool、worker、public-api、migration,以及 example、config 和 test,這些雖然是前端但不是產品本身)。這是地圖的使用者介面端。
  • 熱點(Hotspots) — 排名,附帶一個 why 欄位,說明是哪個術語將該檔案置於該位置:depended-on、churn、complex 或 recent。一個因 churn 而位於頂部的檔案與因 depended-on 而位於頂部的檔案是截然不同的動物;該欄位會告訴你該進行哪種對話。
  • 前端到引擎的路徑(Surface → engine paths) — 從端點或按鈕到核心部分的實際匯入鏈,由 BFS 計算。跨越惰性 await import() 邊緣的路徑會被標記,因為它是在呼叫時而非載入時解析的。
  • 匯入循環群組(Import cycle groups) — 基於靜態值邊緣的強連通集合,並展示一個真實的有向循環。僅型別和惰性(await import(...))邊緣被排除,因為兩者都不會構成真正的初始化循環。
  • 無法觸及的檔案(Unreachable files) — 死程式碼,或啟發式方法遺漏的前端。請判斷是哪一種,並說明你的判斷。

2.5. 閱讀儲存庫已為你撰寫的地圖

在打開任何熱點檔案之前,請檢查 AGENTS.md、CLAUDE.md、ARCHITECTURE.md 或每個目錄的 README — recon.md 會列出它們。一個提供了子系統地圖的儲存庫,能在三十行程式碼中給你掃描需要兩秒推斷、而散文需要一小時重建的資訊。先閱讀這些文件,然後使用掃描結果來驗證它們:文件會過時,圖形不會。

3. 只讀取測量結果指向的內容

按此順序閱讀,然後停止:

  1. 未提交的差異和當前分支的提交(他們現在正在做什麼)。
  2. 最接近的 3–5 個已合併 PR 所更改的檔案(他們剛剛決定了什麼)。
  3. 來自 scan.md 的前 8–15 個熱點檔案。
  4. 對於前 3 個熱點中的每一個,沿著其 reachedVia 前端向內走訪,以便你能夠陳述從使用者操作到引擎的完整路徑。
  5. README、步驟 2.5 中的代理說明文件,以及任何標題與熱點匹配的文件。

第一輪不要開啟這個集合之外的檔案。如果某些東西看起來遺漏了,那是一個需要報告的發現,而不是隨意瀏覽的許可。

4. 在撰寫之前進行驗證

表格是一組線索,而非結論。在將每個主張寫入 BEGIN.md 之前:

  • 開啟檔案並確認你將引用的那行程式碼確實如你所想。
  • 對於前端到引擎的路徑,確認該匯入確實存在於原始碼中。
  • 對於任何與行為相關的內容,優先選擇一個證明該行為的測試,而不是一個看起來像的函式。
  • 使用 grep 搜尋熱點路徑中是否存在被吞沒的錯誤 — catch {}、.catch(() => {})、as any、as never、丟棄的回傳值。錯誤存在於異常被拋棄的地方,而這些是你第一天就能回饋的最高價值發現。
  • 至少花一輪嘗試反駁你的主要主張,而不是確認它。一份好的 BEGIN.md 中最有價值的句子是那些與掃描結果矛盾的句子。

如果掃描結果在某件事上是錯誤的,請在 BEGIN.md 中說明並修正它。一個圖形認為是死的、但實際上透過 HTTP 或佇列觸及的檔案,是你所能記錄的最有用的東西,因為其他人也不會再找到它。將此類入口點宣告在 .begin/surfaces.txt 中(每行一個路徑,可選 path<TAB>kind),下一次執行時就會將它們視為前端。

5. 撰寫 BEGIN.md

使用 references/BEGIN-template.md,並先閱讀 references/EXAMPLE-BEGIN.md 來校準 — 這是一個真實的範例,不是模擬的。結構,按順序:

  1. 用一段話說明此系統的功能 — 使用使用者的語言,而非程式碼的術語。
  2. 基本機制 — 第一原理。核心轉換是什麼?讓其他一切變得顯而易見的一個想法是什麼?少了它什麼會崩潰?
  3. 前端到引擎 — 來自 scan.md 路徑的表格,每一行都經過驗證。如果沒有行跨越進程或網路邊界,請明確說明:在一個拆分語言(split-language)的儲存庫中,真正的接縫通常是 任何匯入圖都無法看到的 HTTP 或佇列呼叫。
  4. 複雜部分排名 — 先寫發現,後寫測量。每個條目需要一個陷阱,引用一個尚未在其測量行中的 檔案:行程式碼。如果你無法提供這樣的條目,代表你並未真正閱讀它:請刪除它。
  5. 決策及其原因 — 每個都連結到它的 PR 或提交,並附上 PR 內文中的推理。這使得文件成為知識圖譜,而不是程式碼導覽。
  6. 你上次離開的地方 — 或者,對於你不擁有的儲存庫,誰擁有這個以及它在哪裡成長:活躍的作者、最新的開放 PR 正在添加什麼、應該先閱讀哪一個。
  7. 機器層在此無法看到的內容 — 以及開放問題,包括那個承載最多負荷的單一假設。永遠不要省略這個。

同時記錄如何執行和驗證它(recon.md 從 package.json 提取的腳本)以及一個詞彙表,用於任何在此儲存庫中被重載的詞彙。這兩者都是新手最先需要的,也是每次程式碼導覽都會忘記的。

使用 [[wiki-style]] 錨點進行交叉連結。為每個章節蓋上印章:

<!-- begin:section id="ingestion" sha="0055f01" files="src/adapter.ts,src/identity.ts" -->

sha = 你推導該章節時(而非後來新增 BEGIN.md 的提交)的 git rev-parse --short HEAD。files = 該章節主張所依賴的檔案;像 src/engine/** 這樣的 glob 模式也可以。一個沒有 files= 的章節,或 files= 指向一個不存在路徑的章節,永遠不會過時,並會被報告為無法驗證 — 而這正是這個技能要防止的失敗,所以請確保路徑是正確的。

6. 使其成為活的文件

bash $S/install-hook.sh          # post-commit;針對另一個觸發器使用 --pre-push

該鉤子會重新執行掃描,並列印一行通知,告知有多少章節已過時,詳細資訊在 .begin/stale.md 中。它會遵守 core.hooksPath(husky)和 Git 工作樹,追加到現有鉤子而不會破壞它,拒絕追加到非 shell 鉤子,並且永遠不會觸碰已追蹤的檔案。使用 --uninstall 移除它,這只會移除其自己的區塊。

/begin update

當使用者返回一個已經有 BEGIN.md 的儲存庫時:

node $S/refresh.mjs && cat .begin/stale.md

只重寫過時的章節,重新執行 recon.sh 以重新整理第 6 章節,並用新的 HEAD sha 重新蓋章每個重寫的章節。保持目前未更改的章節逐位元組一致 — 一個重寫所有內容的更新會同時破壞讀者對變更內容的感覺以及 Git 歷史記錄的實用性。

如果還沒有 BEGIN.md,那麼 /begin update 就等同於 /begin:寫一個。

回饋報告

一段簡短的段落:基本機制、最重要的一兩個檔案及其原因、使用者上次離開的地方,以及唯一一個你無法驗證的事情。細節存在於 BEGIN.md 中,而不是回覆中。

以你沒有檢查的內容作為結尾。一個聲稱有完整覆蓋率的 begin 初步檢查是在說謊。

已知限制 — 請陳述這些限制,不要掩蓋它們

  • 匯入圖是靜態的。一個字面上的 import('./x') 會被解析(並標記為惰性);一個計算出的 import(expr)、一個 DI 容器,或一個由字串鍵入的註冊表不會產生任何邊緣(edge),因此這樣的檔案可能看起來無法觸及,但實際上是承擔重要職責的。在一個拆分語言(split-language)的儲存庫中,前端↔後端的接縫是 HTTP 或 WebSocket 呼叫,並且在建構上是不可見的。掃描會精確地標記無法觸及的檔案,以便人類進行判斷。
  • 完整的 JS/TS 和 Python 解析 — 包括 tsconfig paths(樹中的每個設定檔,而不只是根目錄)、extends、專案 references、NodeNext ./x.js → x.ts,以及針對推斷根目錄(針對 CPython ast 基礎事實測量約 98% 的召回率和精確度)的 Python 絕對、相對和子模組匯入。Go、Rust、Ruby、Java、Kotlin、Swift、PHP、C# 和 C/C++ 完全不貢獻任何邊緣。 在這樣的儲存庫中,每個檔案都顯示出基礎層級的重要性,並顯示為「無法觸及」;掃描會發出警告,你必須重複該警告,而不是將一個空圖形作為一個發現來報告。
  • complexityProxy 會針對每種語言計算決策點,在移除註解和單行字串的程式碼中進行。標記語言和 schema 檔案預設得分為 0;供應商(vendored)、最小化(minified)和產生的檔案會被偵測並單獨排名。多行模板字面量仍會被計算,因此一個模板較多的檔案會顯得稍微熱一些。
  • 變更記錄(Churn)受 --since 限制,而淺層或全新的克隆則沒有任何變更記錄 — 掃描會大聲說明這一點。一個在兩年前被重寫一次的檔案,分數仍然接近於零,而且仍然可能是儲存庫中最重要的檔案。

測試

node $S/test-scan.mjs                   # 圖形、循環、前端、可達性、Python
node $S/test-scan.mjs --mutate pyDotDot # ...並證明斷言可以被觸發為紅色
bash  $S/test-living.sh                 # 過時、鉤子、工作目錄整潔度
node  $S/redact.mjs --self-test         # 秘密被捕獲且乾淨文字不受影響

每個斷言的存在都是因為那個錯誤曾經是真實的並被交付過一次。突變:alias、jsToTs、valueCycle、typeCycle、pyAbsolute、pyDotDot — 每個都必須將其斷言變成紅色,如果沒有,CI 就會失敗。

相關技能