Communityライティング&編集github.com

buildinternet/releases

製品リリースノートのレジストリ。エージェント向けに設計されており、MCPとCLIを介して最近の製品変更履歴を取得できます。

releases とは?

このスキルは、AIエージェント(特にClaude Code)が製品のリリースノート(チェンジログ)を効率的に収集・管理するためのレジストリシステムです。MCP(Model Context Protocol)とCLIの両方のインターフェースを提供し、エージェントがプログラム的に最新のリリース情報を取得できるようにします。 「ローカルインジェスト」と呼ばれるワークフローが特徴で、サーバーサイドのAI抽出処理をバイパスし、エージェント自身がWebページを取得・解析・構造化してバッチエンドポイントに書き込みます。これにより、リモートAPI呼び出しによる推論コストを削減し、トークン消費をエージェントのセッション内に限定できます。 主にClaude Codeのローカルセッションで使用されることを想定しており、エージェントツールによるサブエージェントのファンアウト機能や、ローカルファイルシステムを活用します。また、publisherのオプトアウトポリシー(robots.txtのContent-Signal)を尊重するプリフライトチェックが必須で、倫理的なデータ収集を保証します。 チーム運用においては、新しいソースのオンボーディング、リモート抽出が失敗した際の代替手段、またはフィードが存在しない場合に特に有用です。ただし、クリーンなフィードが利用可能な場合や、マネージドエージェントセッションでは通常の取得パスを使用すべきです。

対応✓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に質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

ローカルインジェスト

リモートフェッチパスを経由せずにチェンジログをオンボーディングします。リモートパス(releases admin source fetch → POST /v1/workflows/update → APIワーカーのDeterministicUpdateWorkflow、#1946)は、サーバーサイドで本文→レコード抽出(インクリメンタルHaikuまたはツールループ)を実行し、その推論に課金します — たとえリリースがゼロ件でもです。ローカルのClaude Codeエージェントは、Webフェッチとファイルツールを備えた有能なモデルであるため、ページごとの抽出をインラインで(すでに開始しているセッション内で)実行でき、決定論的な書き込みパスのみが必要です。

核となる原則: エージェントが抽出者です。 あなたがフェッチし、解析し、レコードを構造化し、それらをバッチエンドポイントにPOSTします。バッチエンドポイントは挿入時にAIを使用せずに、単純な冪等なアップサートを実行します。リモート抽出ループは決して実行されません。

ローカルClaude Codeのみ。 このスキルは、サブエージェントファンアウトのためのAgentツールを使用し、永続的なローカルファイルシステムとCLIのRELEASES_API_*環境変数を想定しています。これはseeding-playbooksと並んで、ローカル専用のオペレータースキルとして位置付けられています — マネージドエージェントフリートにはデプロイされません。

コスト契約

大規模な実行の前に、オペレーターにこれを明示的に伝え、それを遵守します:

  • 消費するもの: フェッチ+抽出のためのエージェント自身のトークン、およびファンアウトするサブエージェントのトークン(モデルは選択可能 — 品質重視ならsonnet、バルク処理ならhaiku)。
  • 消費しないもの: サーバーサイド抽出(更新ワークフローのインクリメンタルHaiku / ツールループパス)は不要。リモートのweb_fetch抽出も不要。POST /v1/workflows/updateは決して呼び出されません。
  • バッチエンドポイントは挿入時にAIを実行しません — 要約、マーケティング分類器、フィードエンリッチメントはありません。insertと、fire-and-forgetのベクトル埋め込み(waitUntil)を実行します。AIフィールド(title_generated / title_short / summary)は意図的に空のままにされます。意図的なフォローアップパスについては、以下の_手動エンリッチメント_を参照してください。

リモート実行が行われなかったことを確認する否定的なシグナル: Axiom releases-cloudflare-logs に POST .../fetch?sessionId=det-… がなく、そのソースに対する extract-deps-worker イベントもありません。

使用すべき場合

  • 新しいソースをClaude Codeで対話的にオンボーディング(または既存のソースをバックフィル)しており、リモート抽出コストをスキップしたい場合。
  • リモートフェッチが完全な抽出ループを消費したにもかかわらず0件のリリースを書き込んだ場合(Conductor / 大規模ボディ / max_tokens 障害モード)— インライン抽出はループを完全に回避します。
  • ページが自身のWebツールでフェッチ可能な場合(以下の拒否はポリシーゲートであり、フェッチ制限ではありません)。

使用すべきでない場合:

  • マネージドエージェントセッションにいる場合。 これはローカル専用です(Agentツールファンアウト + ローカルファイルシステム + CLI環境)。MAセッションでは通常のフェッチパスを使用し続けるべきです。
  • ソースがクリーンでコンテンツ豊富なフィードを持っている場合。 単に追加して(managing-sources)、cronパイプラインにフェッチさせます。ローカルインジェストは、インラインで抽出を行うエージェントが適切なツールである場合のためのものであり、フィード/GitHubアダプターの代替品ではありません。
  • パブリッシャーがオプトアウトしている場合(プリフライトが拒否 — ステップ1を参照)。

ワークフロー

ステップ1 — プリフライト(必須の安全ゲート)

何かをフェッチまたは書き込む前に、オプトアウトチェックを実行します:

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

これはrobots.txtをフェッチし(apex→wwwリダイレクトに従う)、Cloudflare Content Signals ポリシーを解析し、終了コードでゲートします:

終了コード判定アクション
0proceed許容的、または不在 — 続行。
1refuseai-input=no が宣言されています。停止。ユーザーに通知。 フェッチも書き込みもしないでください。
2unknownrobots.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)。ローカルオンボードは、パブリッシャーのオプトアウトに反して、静かにトークンを消費したりコンテンツを取り込んだりしてはなりません。conductor.build は拒否されなければなりません(そのai-input=noにより)— このゲートのリグレッションターゲットです。

拒否はポリシー上の選択であり、技術的な制限ではありません: web_fetch と CF Browser Rendering はこれらのページを依然として取得できます(Conductorに対してシグナルを強制していたのはCloudflareの/crawlエンドポイントのみです)。それでもオプトアウトを尊重してください。オペレーターによって文書化された明示的なパブリッシャー許可がある場合のみ上書き可能です — 黙認のバイパスはありません。

プリフライトはrobots.txtからSitemap: URLも出力します — ステップ3のために保持しておいてください。

ステップ2 — ターゲットの解決

書き込みの前に、組織とソースが存在することを確認します — リリースはsource_idにアタッチされます。作成/命名/プライマリルールについては**managing-sourcesを、構造化フィードが存在するかどうか(存在する場合は通常のパイプラインを優先)についてはfinding-changelogs**を参照してください。その後:

  • 解析ヒントのために組織のプレイブックを読む: releases admin playbook <org>(managing-sources → プレイブックを参照)。
  • 作成/解決された行から**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で1回フェッチ。
  • インデックス → 詳細 → リリースごとのURLを列挙します。/sitemap.xml(プリフライトが表示したもの)をチェンジログパスにフィルタリングして優先的に使用し、そうでなければインデックスHTMLを解析してリリースごとのリンクを取得します。
  • クライアントレンダリングされたインデックス → インデックスはJSシェルであり、そのカードはクライアントサイドフェッチを介して読み込まれるため、curl/非JSスクレイピングでは0件のエントリを返します。レンダリングによって列挙します: Chrome内のClaudeでインデックスを駆動するか(またはレンダリングサブエージェントをファンアウトする)、リストがウィンドウ化されている場合はページネーションし、リリースごとのリンクを収集します。次に、_詳細_ページが静的にレンダリングされているかどうかを確認します — インデックスがそうでない場合でも、多くの場合そうなっています — そして該当する場合はそれらを直接一括curlします(HTML→markdownをローカルで、レンダリング不要、AI課金なし)。Harveyの help.harvey.ai/release-notes がまさにこれです: クライアントレンダリングされたインデックス、静的な詳細ページ。インデックスの空の非JSスクレイピングから「リリースなし」と結論付けないでください。

最近のウィンドウに制限します(デフォルトは最新の約25~50件のリリース)そしてスキップしたものをログに記録します — 決して静かに切り捨てないでください。再実行は冪等であるため、後でのより深いバックフィルは単に行を追加するだけです。

ステップ4 — フェッチ + 抽出

タイプ/バージョン/日付/メディアについては**parsing-changelogs**の規則を再利用します(以下の_パリティ_を参照)。

  • 少数のページ: このエージェント内でインラインでフェッチおよび抽出します。
  • 多数のページ: 並列サブエージェントをファンアウトします — それぞれが1つの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 はnull許容であり、repo はnoopにできるため、これらはAnthropicキーのみで実行されます(証明: scripts/smoke-toolloop.ts)。これはエージェントトークンを直接のAnthropic APIトークンと交換しますが、プロダクションツールループを正確に再現します。これらのパッケージは private: true であり、モノレポからのみ到達可能で、シンCLIからは決して到達できません。デフォルトはアプローチB(エージェントが抽出者)のままです。

ステップ5 — 書き込み(バッチアップサート)

レコードをバッチエンドポイントにチャンク単位でPOSTします(~50/リクエストでリクエストを抑制し、ハンドラーはサーバーサイドでD1バインド制限チャンクを実行します):

# 組織スコープのパスを使用します。裸の /v1/sources/:slug 形式は、型指定された `src_…` IDのみを受け入れます
# 人間のスラッグは 400 bare_slug_rejected を返します(スラッグは組織スコープです、#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")。 デフォルトはfill-onlyであるため、すでにコンテンツがあるURLに対してリッチなコンテンツを再POSTしても、スタブはそのままです — no-opになります。意図的なセカンドパス(最初にインデックスサマリーをシードし、次に完全な詳細ページ本文+メディアを追加)の場合は、バッチボディのトップレベルに "mode": "upsert-content" を追加します: 同じURLの衝突時にコンテンツ/メディアを上書きし、スクレイプタイトルの重複排除プリフィルターをスキップします(#1526)。意図的なエンリッチメントにのみ使用します。デフォルトパスはfill-onlyのままなので、ルーチンの再フェッチが上書きすることはありません。urlはシードされた行と同一でなければなりません — エンリッチメントはURLをキーとするため、URLスキームが変更されると重複が挿入されます。URLスキームが変更された場合は、代わりに再シードします: 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 (型指定ツール)

リリースに空でないタイトル、日付、コンテンツ、メディアがあることを確認します。行が_空_の場合は、抽出を修正して再実行します — デフォルトのアップサートは空の行を安全にバックフィルします。行にすでに_薄いが空ではない_コンテンツがある場合(例えば、今は完全な本文に置き換えたいインデックスサマリースタブ)、プレーンな再実行はno-opです — ステップ5の mode: "upsert-content" エンリッチメント再POSTを使用します。

ソースをリカバリー中で、オンボーディング中ではないですか? このステップは何が書き込まれたかを確認するだけであり、何が書き込まれなかったかについては何も語りません。誰かにソースが「リカバリーされた」または「欠落はない」と伝える前に、backfilling-sources → ソースを「クリーン」または「リカバリー済み」と宣言する前に を参照して、必要なライブページスポットチェックを行ってください。

ステップ7 — プレイブックノート

このソースがどのように取り込まれたかを記録して、将来のエージェントがそれを再導出しないようにします。manage_playbook(アクション update_notes)または releases admin playbook <org> --notes-file - を介して行います。ソースがローカルで取り込まれたこと(まだcronパス上にないこと)、観測されたケイデンス、および抽出の癖を記述します。managing-sources のプレイブック作成ルーブリック(命令形、keep-test、### Fetch instructions / ### Traps / ### Coverage)に従います。

…

[翻訳のために切り詰められました]

関連スキル