Community寫作與編輯github.com

buildinternet/releases

產品發布說明登記系統,專為 AI 代理設計。透過 MCP + CLI 取得最新的產品更新日誌。

releases 是什麼?

此技能提供一個本地端(非遠端)的產品發布說明攝取工作流程,專為 Claude Code 代理設計。其核心原則是讓 AI 代理本身擔任內容提取器:代理負責擷取網頁、解析內容、結構化資料,最後將記錄批次寫入資料庫,整個過程中伺服器端不執行任何 AI 推理,從而完全避免遠端提取的推理費用。 此流程會先執行強制的預檢(Preflight)步驟,檢查目標網站的 robots.txt 是否有 `ai-input=no` 等禁止爬取的政策,以遵守發佈商的意願。接著,它會引導用戶進行頁面分類、提取細節(支援代理分支派遣以處理大量頁面),並最終使用確定性的批次寫入端點進行上傳。 最後一個步驟是驗證攝取結果,並在組織的操作手冊(Playbook)中記錄攝取方式,以便未來的代理能保持一致。對於那些發送遠端提取請求會失敗或成本過高的情況,此技能尤其有用,特別是當遠端提取循環因模型 token 限制等原因而無法產生任何結果時。它支援以 `sonnet` 模型確保提取品質,或以 `haiku` 模型進行大量處理,開發者可以自行選擇。

相容平台✓Claude Code~Codex CLI~Cursor
npx skills add buildinternet/releases

Installed? Explore more 寫作與編輯 skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

在你喜歡的 AI 中提問

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

說明文件

本地攝取 (Local Ingest)

在不觸發遠端提取路徑的情況下,將變更日誌上線。遠端路徑(releases admin source fetch → POST /v1/workflows/update → API 工作者的 DeterministicUpdateWorkflow, #1946)會在伺服器端執行內容主體→記錄的提取(增量 Haiku 或工具迴圈),並對該推理進行計費——即使它寫入了 0 條發布。本地的 Claude Code 代理已經是一個具備網路擷取和檔案工具能力的模型,因此它可以內聯(在您當前的工作階段內)執行每頁的提取,而只需要一個確定性的寫入路徑。

核心原則:代理就是提取器。 您負責擷取、解析、結構化記錄,並將它們 POST 到批次端點,該端點只會執行純粹的冪等向上插入(upsert),在插入時不執行任何 AI 操作。遠端提取循環永遠不會執行。

僅限本地 Claude Code。 此技能使用 Agent 工具進行子代理分支派遣,並假設存在持久的本地檔案系統以及 CLI 的 RELEASES_API_* 環境變數。它與 seeding-playbooks 並列,作為一個純本地操作員技能——不會部署到受管代理集群。

成本合約

在大規模執行之前,請向操作員明確說明並遵守以下規定:

  • 花費: 代理自身用於擷取和提取的 Token,以及您派遣的任何子代理的 Token(模型由您選擇——追求品質用 sonnet,大量處理用 haiku)。
  • 不花費: 不會有伺服器端提取(更新工作流程的增量 Haiku/工具迴圈傳遞),不會有遠端 web_fetch 提取。POST /v1/workflows/update 永遠不會被呼叫。
  • 批次端點在插入時不執行任何 AI 操作——不進行摘要、行銷分類、或資訊饋送增強。它執行 insert 加上一個發射後不理的向量嵌入(waitUntil)。title_generated / title_short / summary 等 AI 欄位會故意留空;請參閱下方的_手動增強_以了解預期的後續補救路徑。

確認未發生遠端執行的負面訊號:在 Axiom 的 releases-cloudflare-logs 中,不會有 POST .../fetch?sessionId=det-… 日誌,也不會有 extract-deps-worker 事件。

使用時機

  • 在 Claude Code 中以互動方式為新資料來源上線(或回溯補齊現有資料來源),並希望跳過遠端提取成本。
  • 遠端提取耗費了完整的提取循環卻寫入了 0 條發布(Conductor / 大型主體 / max_tokens 失敗模式)——內聯提取可以完全繞過該循環。
  • 該頁面可以透過您自己的網路工具擷取(下方的拒絕是策略閘道,而非擷取限制)。

何時不應使用:

  • 您在受管代理工作階段中。 此流程僅限本地(需要 Agent 工具分支派遣 + 本地檔案系統 + CLI 環境)。受管代理工作階段應繼續使用正常的提取路徑。
  • 該資料來源有乾淨、內容豐富的資訊饋送。 直接新增它(managing-sources),讓排程的管線去擷取。本地攝取適用於由代理內聯提取是正確工具的情況,而不是用來取代資訊饋送/GitHub 轉接器。
  • 發佈商選擇退出(預檢拒絕——請參閱步驟 1)。

工作流程

步驟 1——預檢(強制安全閘道)

在擷取或寫入任何資料之前,先執行選擇退出檢查:

bun .claude/skills/local-ingest/preflight.ts <url> --json

它會擷取 robots.txt(遵循 apex→www 重新導向),解析 Cloudflare Content Signals 政策,並根據退出碼進行閘控:

退出碼判決動作
0proceed許可或不存在——繼續。
1refuse宣告了 ai-input=no。停止。向使用者說明情況。 不要擷取或寫入。
2unknown無法擷取/解析 robots.txt。重試一次;如果仍然未知,則向使用者說明情況——不要假設可繼續。

閘控僅針對 ai-input。 本地攝取是搜尋/輸入的攝取——饋送搜尋索引——這正是 ai-input 所管轄的。ai-train=no 是選擇退出模型訓練,此流程不會執行此操作,因此單獨的 ai-train=no(例如 vercel.com)會正確地繼續執行。

這是 Conductor 的教訓。 conductor.build 提供 Content-Signal: ai-train=no, search=yes, ai-input=no——其組織/資料來源早已因此原因在註冊表中暫停(releases admin playbook conductor)。本地上線絕不能違反發佈商的選擇退出而默默地花費 Token 或攝取內容。conductor.build 必須被拒絕(因其 ai-input=no)——這是此閘道的回歸測試目標。

此拒絕是策略選擇,而非技術限制:web_fetch 和 CF Browser Rendering 仍然可以擷取這些頁面(只有 Cloudflare 的 /crawl 端點對 Conductor 強制執行了此訊號)。無論如何,請尊重選擇退出。僅在操作員記錄了明確的發佈商許可時才覆寫——沒有靜默的繞過方式。

預檢還會印出 robots.txt 中的任何 Sitemap: URL——將它們保留給步驟 3 使用。

步驟 2——解析目標

確保組織和資料來源在寫入之前已存在——發布會附加到 source_id。建立/命名/主要規則請參閱 managing-sources,判斷是否存在結構化資訊饋送(若有,則偏好正常管線)請參閱 finding-changelogs。然後:

  • 讀取組織操作手冊以取得解析提示:releases admin playbook <org>(參閱 managing-sources → Playbooks)。
  • 擷取已建立/解析的資料列的 sourceSlug 和 src_… id——批次 URL 需要其中一個。

如果資料來源是全新的,請建立它(例如 releases admin source create "<name>" --url <url> --org <org> [--primary]),但不要觸發提取——這會觸發您想要避免的遠端更新工作流程。

步驟 3——映射頁面

對頁面形狀進行分類(releases admin discovery evaluate <url> --json 會報告 pageStructure: single-page | index | unknown):

  • 單頁變更日誌 → 步驟 4 中只需擷取一次。
  • 索引 → 詳情頁 → 列舉每個發布的 URL。優先使用 /sitemap.xml(預檢已找到它)並過濾出變更日誌路徑;否則,解析索引 HTML 以獲取每個發布的連結。
  • 客戶端渲染索引 → 索引是一個 JS 外殼,其卡片透過客戶端擷取載入,因此 curl/非 JS 爬取將返回零條目。透過渲染進行列舉:使用 Claude 在 Chrome 中驅動索引(或派遣一個渲染子代理),如果列表是分頁的則進行分頁,並收集每個發布的連結。然後檢查_詳情_頁面是否為靜態渲染的——即使索引不是,它們通常也是——如果是,則直接大量 curl 那些頁面(HTML→markdown 在本地執行,無需渲染,無 AI 費用)。Harvey 的 help.harvey.ai/release-notes 正是如此:客戶端渲染的索引,靜態的詳情頁面。不要因為索引的非 JS 爬取結果為空就得出「沒有發布」的結論。

限制在一個近期視窗內(預設約 25–50 條最新發布),並記錄您跳過了哪些內容——絕不要默默地截斷。重新執行是冪等的,因此稍後更深入的回溯補齊只會新增資料列。

步驟 4——擷取 + 提取

重複使用 parsing-changelogs 中關於類型/版本/日期/媒體的約定(請參閱_對等性_)。

  • 少量頁面: 在此代理中內聯擷取和提取。
  • 大量頁面: 派遣平行的子代理——每個子代理處理一個 URL 切片,每個子代理以批次模式返回記錄。使用 seeding-playbooks(以及 superpowers:dispatching-parallel-agents 以了解分支派遣規範)中的 Agent 工具派遣模式。不要在父代理中擷取發布 URL——將其委派出去以保持父代理的上下文乾淨。
  • 父代理儲存注意事項: 子代理可能因權限限制而無法執行批次寫入。預先規劃——讓每個子代理在其結果中返回記錄,並讓父代理(您)在步驟 5 中執行寫入。這與 seeding-playbooks 用於儲存筆記的模式相同。
  • 提取媒體——不要只提供文字。 從每個發布主體中提取圖片/影片並填入 media,並將 _next/image / _vercel/image 優化器包裝展開為底層的 CDN URL(packages/rendering/src/media-url.ts 中的 normalizeMediaUrl)。僅傳遞文字的第一輪是常見的缺失,只有在操作員審查時才會被發現(Harvey 最初僅提供了文字,後來不得不重新提取 _next/image → cdn.sanity.io 並重新播種);增強後的重新 POST 使用 mode: "upsert-content"(步驟 5)。

每條記錄必須符合批次模式(請參閱步驟 5)和對等規則。

可選——確定性提取(方案 A,僅限單一儲存庫): 除了手動提取,您也可以呼叫 packages/adapters/src/extract/ 中的生產級提取庫——extractFromBody、extractWithTools、runDirectFetchExtraction。ExtractDeps.cloudflare 是可為空的,repo 可以是一個空操作,因此它們只需一個 Anthropic 金鑰即可運行(證明:scripts/smoke-toolloop.ts)。這會用代理 Token 換取直接的 Anthropic API Token,但會精確地複製生產級工具迴圈。這些套件是 private: true——只能從單一儲存庫訪問,永遠無法從精簡 CLI 訪問。預設仍然是方案 B(代理即提取器)。

步驟 5——寫入(批次向上插入)

將記錄以批次方式 POST 到批次端點,每批約 50 條(保持請求大小合理;處理器會在伺服器端進行 D1 綁定限制的分塊):

# 使用組織範圍的路徑。單純的 /v1/sources/:slug 格式只接受一個有類型的
# `src_…` id——人類可讀的 slug 在那裡會返回 400 bare_slug_rejected(slug
# 是組織範圍的,#690)。使用有類型的 id 時,單純的路徑格式也能運作:
#   POST $RELEASES_API_URL/v1/orgs/<orgSlug>/sources/<sourceSlug>/releases/batch
#   POST $RELEASES_API_URL/v1/sources/<src_…>/releases/batch
curl -sS -X POST "$RELEASES_API_URL/v1/orgs/<orgSlug>/sources/<sourceSlug>/releases/batch" \
  -H "Authorization: Bearer $RELEASES_API_KEY" \
  -H "Content-Type: application/json" \
  -d @chunk.json   # { "releases": [ … ] }

每條發布的欄位(實際接受的形狀——workers/api/src/routes/sources.ts,postReleasesBatchHandler):

{
  "version": "1.4.0", // 可選;對於以日期為首或部落格類型的資料來源,可省略或設為 null
  "title": "深色模式", // 必填
  "content": "Markdown 主體…", // 必填
  "url": "https://…/changelog/dark-mode", // 可選但**務必填寫**——它是去重鍵
  "contentHash": "…", // 可選
  "publishedAt": "2026-05-30", // 可選;ISO-8601(參閱對等性)
  "media": "https://…/shot.png", // 可選
  "type": "feature", // 可選;"feature" | "rollup"
  "prerelease": false, // 可選
}
  • 冪等。 根據 UNIQUE(source_id, url) 進行向上插入,填充而非覆蓋:發生衝突時,僅當儲存的行中對應欄位為_空_時,才會回填內容/媒體,因此重新執行永遠不會覆蓋好的行。可以安全地重新執行和分頁——相同的 url 會更新而非重複。
  • 增強後的重新 POST(mode: "upsert-content")。 由於預設是僅填充,為一個已有內容的 URL 重新 POST 更豐富的內容將是空操作——佔位內容會保留。對於有意的第二輪處理(先播種索引摘要,再補上完整詳情頁主體 + 媒體),在批次主體的頂層添加 "mode": "upsert-content":它會在相同 URL 衝突時覆蓋內容/媒體,並跳過爬取標題的去重預過濾器(#1526)。僅在有意增強時使用;預設路徑保持僅填充,以便例行重新擷取不會覆蓋內容。url 必須與已播種的行完全一致——增強依賴 URL 作為鍵,因此更改 URL scheme 會導致重複插入而非更新。如果 URL scheme 改變了,請重新播種:releases release delete --source <src_…> --hard 然後執行新的 /batch(使用預設模式)。
  • 驗證。 需要 write 權限;靜態的 RELEASES_API_KEY(root)滿足此條件。在此儲存庫中,.env 會自動載入 RELEASES_API_URL + RELEASES_API_KEY。
  • 插入時不執行 AI 操作(請參閱成本合約)。

分塊輔助工具(讀取 records.json 陣列,每批 50 條進行 POST):

bun -e '
const orgSlug = process.argv[1], sourceSlug = process.argv[2], file = process.argv[3];
const all = JSON.parse(await Bun.file(file).text());
const base = process.env.RELEASES_API_URL, key = process.env.RELEASES_API_KEY;
for (let i = 0; i < all.length; i += 50) {
  const releases = all.slice(i, i + 50);
  const res = await fetch(`${base}/v1/orgs/${orgSlug}/sources/${sourceSlug}/releases/batch`, {
    method: "POST",
    headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
    body: JSON.stringify({ releases }),
  });
  console.log(`chunk ${i / 50}: ${res.status} ${(await res.text()).slice(0, 200)}`);
}
' <orgSlug> <sourceSlug> records.json

步驟 6——驗證

releases tail <slug> --json   # 或:get_latest_releases(類型化工具)

確認發布具有非空的標題、日期、內容和媒體。如果某行是_空_的,修正提取並重新執行——預設的向上插入會安全地回填空行。如果某行已經有_薄但非空_的內容(例如您現在想用完整主體替換的索引摘要佔位內容),單純的重新執行是空操作——請使用步驟 5 中的 mode: "upsert-content" 增強重新 POST。

是在恢復一個資料來源,而非上線一個新的? 此步驟僅確認已寫入的內容——它無法說明未寫入的內容。在告訴任何人某個資料來源已「恢復」或「沒有缺失任何東西」之前,請參閱 backfilling-sources → 在宣告資料來源「乾淨」或「已恢復」之前,了解所需的即時頁面抽查。

步驟 7——操作手冊備註

記錄此資料來源的攝取方式,以便未來的代理無需重新推導。透過 manage_playbook(update_notes 動作)或 releases admin playbook <org> --notes-file - 進行。備註中應說明該資料來源是本地攝取的(尚未納入 cron 路徑)、觀察到的發佈頻率,以及任何提取特性。請遵循 managing-sources 中的操作手冊撰寫規範(使用命令語氣、保持測試、### Fetch instructions / ### Traps / ### Coverage)。

...

[內容因翻譯而截斷]

相關技能