Skip to content
Skillv1.0.0

llm-wiki

Claude Code 知識を raw→wiki にコンパイル蓄積。init/ingest/query/synthesize でボールト初期化・ソース取り込み・引用付き回答・派生成果物生成

by aidotters(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from aidotters/claude-code-wiki-maker (.claude/skills/llm-wiki/SKILL.md). Install upstream with npx skills add aidotters/claude-code-wiki-maker --skill llm-wiki. Copyright stays with the author.

llm-wiki(個人 Claude Code 知識ハブ)

目的: 進化の速い Claude Code の知見を「検索ではなくコンパイル」して永続知識ベースに蓄積し、 引用付きの派生成果物(チートシート/Tips 集)を生成・維持する。

引数: $ARGUMENTS

使用方法:

/llm-wiki init                                          # ボールト初期化・wiki-vault リンク案内・設定整備
/llm-wiki ingest <path-or-url>                              # ソースを取り込みコンパイル(既存)
/llm-wiki ingest <path-or-url> --type=practice              # practice ページとして取り込み(raw/notes/ 想定)
/llm-wiki ingest <path-or-url> --feature=<slug>             # source 生成 + 指定 feature ページ更新
/llm-wiki ingest <url> --watch                              # Tier B URL を watchlist 登録(source ページに watch:true)して取り込み
/llm-wiki ingest <url> --feed=<rss_url>                     # Tier B フィード登録(source ページに feed_url を立て discover-watchlist の巡回対象に)
/llm-wiki ingest --feed=notion-medium-db:default            # document-less ソース登録(Phase 4・feed_registry に append・raw/source ページ生成なし・path-or-url 省略)
/llm-wiki ingest --feed=claude-blog-sitemap:default         # document-less ソース登録(Phase 4c・公式ブログ claude.com/blog を sitemap 経由で discover-watchlist の巡回対象に・path-or-url 省略)
/llm-wiki query <質問>                                      # Wiki から引用付きで回答(読み取り専用)
/llm-wiki synthesize <テーマ>                               # チートシート/Tips 集等を生成/再生成
/llm-wiki lint [--check=<csv>]                              # 17 検査(Phase 2a 7 + Phase 2b 4 + Phase 3a 1 + Phase 3c 1 + Phase 3f 2 + Phase 3g 1 + Phase 5 1、#11 のみ承認制で書き込み)
/llm-wiki refresh-tier-a [--dry-run]                        # Tier A 日次自動再取得(cron / launchd 経由・対話実行も可)
/llm-wiki discover-tier-a [--no-prompt|--dry-run]           # Tier A 未取り込み URL 自動発見 + 承認制 ingest(--no-prompt で cron 用)
/llm-wiki refresh-watchlist [--dry-run]                     # Tier B watchlist(watch:true)の日次自動再取得(cron / launchd 経由・mode F の Tier B 版)
/llm-wiki review [--dry-run]                                # 会話 hook が貯めた URL を triage(承認制 ingest・対話専用)
/llm-wiki discover-watchlist [--no-prompt|--dry-run]        # Tier B フィード登録済みサイトの新着 URL 自動発見 + stage-1/stage-2 フィルタ + 承認制 ingest(--no-prompt で cron 用)

不変条件(CLAUDE.md「設計上の不変条件」が最上位の正)

このスキルは CLAUDE.md の不変条件に従う。齟齬時は CLAUDE.md > SKILL.md / schema.md。 データ規約(ページタイプ・フロントマター必須フィールド・命名/[[wikilink]]/tier 判定・schema_version・ co-evolution・責務境界)の唯一の正は references/schema.md であり、本ファイルでは再記述しない。 ページ本文の雛形は references/page-templates.md

要点(詳細は上記参照):

  • raw は不変スナップショット。すべての主張は raw を引用する。
  • 既存ページと矛盾する主張は黙って上書きせず「矛盾」セクションに両論併記。
  • 操作後は index.md / log.md を更新し、ボールト側 Git に操作単位でコミットする。
  • ボールトパスはハードコードせず、本リポジトリ直下の設定ファイル .llm-wiki.json から解決する。

ステップ0: 引数パースとモード分岐

  1. $ARGUMENTS の第 1 トークンをモードとして取り出す。残りを引数とする。
  2. 分岐:
    • initモード A
    • ingestモード B(第 2 引数 = path-or-url。無ければ使用法表示で停止。例外(Phase 4・§5.2b): --feed=notion-*: スキームが指定され path-or-url が省略された場合は停止せず mode B の registry append 特例に進む=document-less ソース登録のため path-or-url 不要)
    • queryモード C(残り全体 = 質問。無ければ使用法表示で停止)
    • synthesizeモード D(残り全体 = テーマ。無ければ使用法表示で停止)
    • lintモード L(Phase 2a 7 + Phase 2b 4 + Phase 3a 1 + Phase 3c 1 + Phase 3f 2 + Phase 3g 1 + Phase 5 1 の 17 検査)
    • refresh-tier-aモード F(Phase 3a・Tier A 日次自動再取得。--dry-run 任意)
    • discover-tier-aモード G(Phase 3c・Tier A 未取り込み URL 自動発見 + 承認制 ingest。--no-prompt / --dry-run 任意)
    • refresh-watchlistモード W(Phase 3f・Tier B watchlist〔watch: true〕の日次自動再取得。mode F の Tier B 版。--dry-run 任意)
    • reviewモード H(Phase 3e・会話 hook が貯めた URL を triage して承認制 ingest。対話専用。--dry-run 任意)
    • discover-watchlistモード I(Phase 3g・Tier B 登録済みフィード(feed_url 保持 source ページ)の新着 URL 自動発見 + stage-1 keyword フィルタ + stage-2 LLM 判定 + capped バッチ opt-out 承認制 ingest。--no-prompt / --dry-run 任意)
    • 上記以外 / 引数なし → 上の「使用方法」を表示して停止
  3. init 以外のモードは、最初に ボールト前提チェック(ステップ0.5)を行う。

ステップ0.5: ボールト前提チェック(init 以外)

  1. 本リポジトリ直下の設定ファイル .llm-wiki.json を Read。無ければ 「先に /llm-wiki init を実行してください」と案内して停止

  2. 設定の vault_relative./wiki-vault)の存在とリンク有効性を Bash で確認 (test -e ./wiki-vault)。不在/リンク切れなら同様に init を案内して停止。

  3. ボールト側に未コミット変更があれば(git -C ./wiki-vault status --porcelain)、 状態を提示し続行可否を AskUserQuestion で確認する。

    • モード F(refresh-tier-a)は対話モードではないため、§F-2 で自動 skip に分岐する(AskUserQuestion を起動しない)。
  4. minitools_path 解決(Phase 4・Medium 機能の availability gate): .llm-wiki.jsonminitools_path を読む。

    • キー不在 or ディレクトリ不在test -d <minitools_path> が false)なら minitools_available = false をフラグし、Medium 関連機能(mode B step 3 の medium 分岐=4a・mode I I-3 の feed_registry Notion 巡回=4b)のみ無効化する。他モード・他経路は通常動作(clean failure・gh 不在と同型)。本チェック自体は停止理由にしない(Medium を使わない利用者は minitools_path 未設定のまま全機能を使える)。
    • キーがありディレクトリも存在すれば minitools_available = true・解決済みパスを各モードに伝搬する。
    • 各モードでの「無効化」の具体挙動は per-fetcher availability check(§モード B 4a・§モード I I-3)に従う(uv 不在 / minitools_path 未設定 / CLI exit 1 を当該経路でのみ clean failure とし、ingest / discover 全体は壊さない)。

ステップ0.6: lock 取得(書き込みモード共通)

.llm-wiki.lock書き込みモード(B / D / F / G / W / H / I、および lint #11 承認制決着の ## 矛盾 編集部分)でのみ取得する。query(モード C)は読み取り専用のため不要。lint 通常実行(17 検査レポート+ wiki/log.md 追記まで)も不要(design.md §6 carve-out)。

  • ファイル: vault 直下 .llm-wiki.lock/llm-wiki init で vault .gitignore に追加済)。
  • フォーマット: 1 行 JSON {"pid": <PID>, "started_at": "<ISO8601>", "mode": "ingest|synthesize|refresh-tier-a|discover-tier-a|refresh-watchlist|review|discover-watchlist|lint-resolve"}
  • atomic 取得: Bash('set -C; echo "{\"pid\":'$$',\"started_at\":\"'$(date -Iseconds)'\",\"mode\":\"<mode>\"}" > ./wiki-vault/.llm-wiki.lock')set -C(noclobber)により既存ファイルへの書き込みは exit non-zero で失敗。失敗時は スタール判定 へ進む。
  • スタール判定: 既存 .llm-wiki.lock を Read し、started_at から 既定 1 時間経過 AND Bash('kill -0 <pid> 2>/dev/null') が non-zero(プロセス死亡)の 両方 が真のときのみ強制奪取(誤奪取防止)。一方だけ真なら他プロセス稼働中扱いとして該当モードの skip 手順に進む。
  • 解放: モード完了時に Bash('rm -f ./wiki-vault/.llm-wiki.lock')。例外時も trap 相当で削除を試みる。

各モードでの lock 取得タイミングは各モード本文の冒頭で指定する。


モード A: /llm-wiki init

ボールトを初期化し、本リポジトリ側の設定を整える。

  1. 設定ファイル確認

    • .llm-wiki.json が既存なら内容を提示し、再初期化するか AskUserQuestion で確認。
  2. ボールト実体パスの確定

    • ./wiki-vault が既に有効なシンボリックリンクならその実体を採用。
    • 無ければ実体パス(既定候補 ~/Documents/claude-code-wiki)を AskUserQuestion で確認し、 ln -s <実体パス> ./wiki-vault案内し、承認を得て実行する。
  3. ボールト骨格生成

    • references/schema.md §3 のディレクトリ規約に従い、raw/wiki/ のサブディレクトリ、 wiki/index.md wiki/log.md wiki/overview.md wiki/current-baseline.md を雛形生成する (既存ファイルは上書きしない)。
    • 各雛形フロントマター/構成は references/schema.mdreferences/page-templates.md に従う。
  4. current-baseline.md の初期 claude_code_version 確定(決定 イ)

    • WebFetch 対象 URL(確定): https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md
      • 取得不可時フォールバック URL: https://github.com/anthropics/claude-code/releases
    • 取得テキストを raw/docs/<取得日 YYYY-MM-DD>-claude-code-release.md に保存し、 原文 URL・取得日時・取得手段・Tier(references/schema.md §4 によりこの取得元は A)を メタとして記録する。
    • current-baseline.md はこの raw を引用して claude_code_version を確定する (不変条件「すべての主張は raw を引用」を init でも満たす)。
    • WebFetch 失敗時のみ: claude --version の実行をユーザーに案内(! claude --version)し、 申告値をセット。raw 引用が無いため current-baseline.md に 「ソース: 手動入力(暫定)・取得日」と明記し、フロントマターは references/schema.md §2 に従い stale を真として記録、 次回オンライン時に Tier A 取得で上書き提案する旨を本文に残す。
  5. schema 軽量ポインタ記録(決定 ウ)

    • current-baseline.mdreferences/schema.md §6 の軽量ポインタを記録する (schema_version / 本リポジトリの該当 commit ハッシュ=git rev-parse HEAD / 規約 1〜2 行サマリ)。 schema 全文は複製しない。
  6. 本リポジトリ側の整備

    • .gitignorewiki-vault 行が無ければ追記する(誤コミット防止)。
    • .gitignore.llm-wiki-inbox.jsonl 行が無ければ追記する(会話 URL hook の vault 外 inbox・誤コミット防止・Phase 3e)。
    • minitools_path の対話設定(Phase 4・任意): Medium 取り込み(4a content routing / 4b Notion DB discovery)に使う外部リポジトリ minitools のパスを AskUserQuestion で確認する(既定候補 /Users/tak/Projects/minitools)。「設定しない(Medium 機能を使わない)」を必ず併置する。「設定しない」が選ばれた場合は minitools_path キー自体を .llm-wiki.json に書かない(キー不在=Medium 機能のみ無効化・他モード通常動作・§ステップ0.5)。パスが選ばれた場合のみ minitools_path キーを生成する。ハードコード禁止(外部リポジトリパスのため設定必須)。
    • .llm-wiki.json を生成する。MVP は相対パス ./wiki-vault を正、絶対パスは参考値、 schema_versionreferences/schema.md の値を転記、minitools_path は上記対話で設定した場合のみ含める:
      { "vault_relative": "./wiki-vault",
        "vault_absolute": "<実体絶対パス>",
        "schema_version": "<references/schema.md の schema_version>",
        "minitools_path": "<minitools 実体パス・設定時のみ>" }
  7. ボールト側 .gitignore 整備

    • vault 直下 .gitignore を Read。存在しなければ作成。
    • .llm-wiki.lock 行が無ければ追記(書き込みモード排他制御の lock ファイルが誤コミットされないため)。
    • .DS_Store 等の既存除外行は維持。
  8. ボールト側 Git 初期化

    • git -C ./wiki-vault init(未初期化時)→ add -A → 初回コミット (メッセージ例 chore: llm-wiki init (schema vX.Y.Z))。
  9. 完了サマリ(生成パス・確定バージョン・schema_version)を提示する。

  10. session-start hook 設定例の案内(参考・自動インストールしない)

    • references/session-start-hook.example.json が同梱されていることを利用者に案内する。
    • この設定例は Claude Code の SessionStart hook で wiki/current-baseline.md(現在の正=claude_code_version / updated / last_tier_a_refresh / migration_pending)を ambient context にロードするためのもの。/llm-wiki query を呼ぶ前に「いま何が真か」を起動時から把握しておく目的。
    • 利用者が 手動で .claude/settings.jsonproject local 推奨・グローバル ~/.claude/settings.json への登録は他プロジェクトでも発火するため非推奨)にマージする想定。/llm-wiki init は自動マージしない(read-only context preload とはいえ利用者設定ファイルの書き換えは行わない方針)。マージ対象は hooks キーのみ(example の _comment / _notes は説明用フィールドなので .claude/settings.json にはコピーしない。Claude Code の settings parser が未知の root key をどう扱うかは保証されないため)。
    • command[ -L ./wiki-vault ] && cat ./wiki-vault/wiki/current-baseline.md 2>/dev/null || trueCWD = リポジトリルート前提・vault 不在時は無音終了matcher: "*" は startup / resume / clear / compact 全部で再注入。narrow したい場合は example の _notes 参照。
  11. 会話 URL hook 設定例の案内(参考・自動インストールしない・Phase 3e)

    • references/conversation-url-hook.example.jsonUserPromptSubmit hook の settings スニペット)と references/conversation-url-hook.example.sh(URL 抽出スクリプト本体)が同梱されていることを利用者に案内する。
    • この hook は会話中のプロンプトに含まれる URL を検出し、repo ルート(CWD)直下 vault 外 .llm-wiki-inbox.jsonl に append する(スキル起動・vault 書き込み・lock 取得は伴わない=検出のみ)。貯めた URL は後で /llm-wiki review(モード H)で triage して承認制 ingest する。
    • 利用者が 手動で .claude/settings.jsonproject local 推奨・グローバルは他プロジェクトでも発火するため非推奨)にマージ対象は hooks キーのみでマージする想定(/llm-wiki init は自動マージしない・session-start hook 同流儀)。スクリプトは冒頭の [ -L ./wiki-vault ] || exit 0CWD = リポジトリルート前提・vault 不在時は無音終了
    • 2 つの example の使い分け: references/conversation-url-hook.example.json既存 settings に hooks スニペットだけ手動マージする教材版(.example.sh を参照・_comment/_notes 付き)。一方このリポジトリ直下の .claude/settings.example.jsonこの repo をそのままクイック有効化する全文設定(active 実体 references/conversation-url-hook.sh を参照)で、cp .claude/settings.example.json .claude/settings.json でコピーするだけで有効化できる。.claude/settings.json.gitignore 済=コミットされないため、クローン/参照しただけの人に UserPromptSubmit hook が自動適用されることはない(opt-in)。

モード B: /llm-wiki ingest [--type=practice|--feature=]

ソースを取り込み、コンパイルする。

lock: ステップ 0.5 ボールト前提チェック直後に取得(ステップ 0.6 参照)。本モード全体を排他制御し、ステップ 9 のコミット後に解放する。例外時も解放を試みる。

  1. lock 取得(ステップ 0.6 の手順)。失敗時はステップ 0.6 の skip 手順に従う。

0.a --feed=<document-less-source>: registry append 特例(Phase 4 4b / Phase 4c 登録・§5.2b・document-less ソース登録): 引数の --feed=<v> を先に検査し、v<source>:<selector> スキーム(<source> が既知 document-less source={notion-medium-db, claude-blog-sitemap} のいずれか・http(s) URL ではない・例 notion-medium-db:default / claude-blog-sitemap:default)かつ path-or-url が省略されている場合、通常 ingest pipeline を short-circuit する:

  • step 0.b(migration_pending 提案)/ step 1〜8.5(raw 確保・同一 source 判定・矛盾検出・overview 更新)をすべて skip(raw を作らず source ページも生成しないため references/schema.md §4.5 の衝突 3 件=lint sources-empty / 不変条件 #2 引用 / mode B raw 前提 pipeline がいずれも発生しない)。
  • v<source>:<selector> に分解(source = : 前=discovery source 種別〔現状 notion-medium-db / claude-blog-sitemap の 2 種〕、selector = : 後〔省略時は default〕)。未知 source 種別(上記 2 種以外)はエラーで中断し許容種別 2 種を案内。
  • Read("./wiki-vault/wiki/current-baseline.md")feed_registry[] を取得。同一 {source, selector} の既存エントリがあれば no-op(重複 append しない・log feed_registry: already registered <source>:<selector> を 1 行追記して step 9 相当へ)。
  • 無ければ feed_registry[] 末尾に {source: <source>, selector: <selector>, label: <利用者に AskUserQuestion で確認した人間可読ラベル・既定 "<source> (<selector>)">, added: <今日>} を append で Edit(references/schema.md §2.1)。
  • wiki/log.mdfeed_registry: register <source>:<selector> (<日付>) を追記し、ボールト Git で current-baseline.md(+ log.md)を 1 commit chore: register feed <source>:<selector>
  • lock 解放(step 10 相当)して終了(以降の step に進まない)。--watch / --feed 非伝播ルールには影響しない(本特例は利用者の直接呼び出しのみ・§5.4)。
  • : --feed=<http(s)_rss_url>(http スキーム)は本特例に当たらず通常 ingest(source ページに feed_url を立てる既存 3g 挙動・step 1 以降)に進む。短絡するのは <source> が既知 document-less source(notion-medium-db / claude-blog-sitemap)かつ path-or-url 省略時のみ。claude-blog-sitemapselector は実用的意味を持たない(default 固定運用)が、スキーマ統一のため {source, selector, label, added} 形を踏襲する。

0.c --backfill-dates 遡及補完特例(Phase 5・一回限りバッチ・§5.2c): 引数に --backfill-dates があり path-or-url が省略されている場合、通常 ingest pipeline を short-circuit し、既存 raw の日付メタを後追い補完する一回限りのバッチを実行する(恒久 cron mode ではない・lint には置かない=lint は frontmatter を変更しない不変条件。ingest が raw frontmatter 書き込みの正規の場=schema §3 source_url 補完前例):

  • step 0.b(migration_pending 提案)/ step 1〜8.5 を skip(個別 ingest pipeline に乗らない)。
  • 対象抽出: Glob('./wiki-vault/raw/**/*.md') で全 raw を列挙し、各 raw を Read(offset=0, limit=30) でフロントマター取得。published_atlast_modified両方とも存在しかつ unknown 以外の raw は skip(補完済み)。少なくとも一方が欠落 or unknown の raw を対象にする。
  • 経路別補完(本文・fetched_at・順序は不可触=E1): 各対象 raw の source_url(無ければ skip + log backfill: no source_url <path>)の host を判定し、本文を再取得せず軽量経路で日付のみ取得:
    • github.com blob → gh api "repos/{o}/{r}/commits?path={p}&sha={ref}&per_page=1"committer.datelast_modifiedgh-commit
    • medium.com → skip(backfill は gh/feed/sitemap/WebFetch の軽量経路のみ。Medium は Playwright 再取得〔scrape-medium・対話・重い〕が必要なため backfill では補完しない。日付が要るなら当該 URL を再 ingest すれば mode B step 3 --emit-meta で乗る。log backfill: medium skipped (needs Playwright re-ingest) <path>)。
    • その他 http(s)(blog / 一般記事 / docs を含む) → WebFetch で (1) 構造化メタ article:*_time/JSON-LD → html-meta、(2) 取れなければ本文可視日付の保守パース → html-bodyreferences/schema.md §3「html-body 保守パース規約」)。claude.com/blog/<slug> の本文 Date: <Month DD, YYYY> はこの (2) で published_athtml-body として回収する(claude.com/sitemap.xml<lastmod> を持たないため sitemap 経路は使わない=dry-run 実証)。なお <lastmod> を持つ sitemap のソースがあれば sitemap-lastmod も可(claude.com は非該当)。
    • 取得不能・保守ルール非充足は当該 raw を unknown のまま据え置き(無理に埋めない)。
  • frontmatter 追記のみ: 取得できた日付 4 フィールドを当該 raw frontmatter に Edit で追記(既存本文・fetched_at・他フィールドは不可触)。
  • index 代表鮮度日の更新: 補完で日付が入った raw を sources: に含む wiki/sources/*.md ページを特定し、wiki/index.md の当該行 (鮮度: …) を再計算・更新(モード B step 9 と同仕様)。
  • commit / log: wiki/log.mdbackfill-dates: scanned=S targets=T filled=F unknown=U (YYYY-MM-DD) を追記し、raw 群 + index.md + log.md を 1 commit chore: backfill raw date metadata (<日付>)。個別 raw の失敗は skip + log で batch 継続。
  • --dry-run: Edit / commit せず対象件数・経路別内訳・would-fill <path>: last_modified=<date>(<source>) をレポート。
  • lock 解放(step 10 相当)して終了(以降の step に進まない)。--backfill-dates は他フラグ(--type / --feature / --watch / --feed)と併用不可(併用はエラーで中断)。

0.b migration_pending 提案(書き込み前・lock 取得直後): モード L §ステップ 2.5 の手順を同一ロジックで適用(候補 1 件でも「適用しない」併置、multiSelect: true、上位 4 件、承認分は 共通 surface 経由で new_url を本モード step 3 (ii) に渡して新規 raw を ingest し既存 source ページに統合+当該 migration_pending エントリ削除+ 1 commit。Phase 3d 共通 surface 設計)。0 件選択は通常 ingest 続行。

  1. 引数パース

    • 第 2 トークン: path-or-url
    • 残りトークンは --key=value 形式(--type=practice / --feature=<slug> / --feed=<rss_url>)と 値なしフラグ --watch(Phase 3f)/ --backfill-dates(Phase 5・path-or-url 省略の一回限りバッチ・step 0.c で short-circuit・他フラグと併用不可)。許容はこの 5 種のみ。未知キーはエラーで中断(メッセージで許容キーを案内)。
    • --type=practice--feature=<slug>同時指定した場合はエラーで中断 (practice は主型、feature は派生型として意味が衝突するため)。
    • --watch(Phase 3f・watchlist 登録フラグ)は --type / --feature / --feed と併用可。 利用者の直接 /llm-wiki ingest でのみ有効で、共通 surface の内部呼び出し(mode G G-6 / mode H H-5 / mode F migration / mode I I-6)からは渡されない(後述「--watch 非伝播」)。
    • --feed=<rss_url>(Phase 3g・フィード登録フラグ): 指定時、生成/更新する source ページのフロントマターに feed_url: <rss_url> を立て、mode I(discover-watchlist)の巡回対象に登録する。利用者の直接 /llm-wiki ingest でのみ有効(共通 surface 内部呼び出しからは渡されない=後述「--feed 非伝播」)。--watch との併用可(--feed = サイト全体の RSS 登録・--watch = 当該 site-url の watchlist 登録として共存。ただし feed_url はサイト全体に付けるのが想定ユースケース)。retrofit(既存 source への後付け登録)は frontmatter に feed_url を手動追記すれば足り、3g では別コマンドを新設しない。
      • document-less スキーム--feed=<source>:<selector><source>{notion-medium-db, claude-blog-sitemap}・path-or-url 省略)は本 step に到達せず step 0.a の registry append 特例で処理済み(feed_registry[] に登録・source ページに feed_url を立てない・§5.2b)。短絡するのは http(s) ではないこの 2 種のみ。
      • --feed=notion-*:<selector> スキーム(Phase 4 4b・document-less ソース登録): 値が http(s) URL ではなく notion-*: スキーム(例 notion-medium-db:default)の場合は step 0.a の registry append 特例で処理済み(本 step には到達しない)。この形式は source ページに feed_url を立てず current-baseline.md.feed_registry[] に登録する(§5.2b)。
  2. 引数判定: URL(http(s)://)か ローカルパスかを判定。

  3. raw 確保(URL は host 別 routing・Phase 4 4a)

    • URL: host を判定して取得経路を分岐する(design §5.1・F-1 gh api routing と同型)。取得後は raw/<種別>/<取得日 YYYY-MM-DD>-<slug>.md に保存し、原文 URL・取得日時・取得手段・tier(references/schema.md §4 で判定)をメタ記録。取得失敗時はユーザーに手動 raw 保存を案内して中断(黙って空ページを作らない)。
      • medium.com / *.medium.com(Phase 4 4a・新設)minitools scrape-medium --cdp 経路:
        1. availability check: ステップ0.5 の minitools_availableminitools_path 設定済み+ディレクトリ存在)を確認。false(未設定 or 不在)なら「Medium 取得には .llm-wiki.jsonminitools_path の設定が必要です」と案内し、当該 URL を中断(raw 未作成・他ソース継続=clean failure・空ページを作らない)。uv 不在も同様に検出して案内・中断。
        2. Bash('uv run --directory <minitools_path> scrape-medium --url "<url>" --cdp --emit-meta') を実行(--emit-meta で stdout 先頭に日付 YAML frontmatter を前置・続けて英語原文 Markdown 本文=memory: minitools-phase4-cli-interface / Phase 5 Phase 2)。
        3. exit 0 → stdout を frontmatter ブロックと本文に分離してから raw/articles/<取得日>-<slug>.md に保存する。
          • 分離規約: stdout の 1 行目が --- なら、その次の --- 行までを emit frontmatter ブロックとみなし、ブロック内の published_at: / last_modified: / published_at_source: / last_modified_source: を読む。2 つ目の --- の次行以降を本文とする(emit frontmatter を本文に混入させない)。1 行目が --- でない(--emit-meta 非対応 minitools 等)場合は stdout 全体を本文とみなし、日付 4 フィールドを unknown にフォールバック(clean degradation・例外にしない)。本文先頭が ---(hr)になる稀な記事も、2 つ目 --- 終端の成立で分離が破綻するなら unknown 退避(偽日付を出さない・design リスク表)。
          • raw 本文 = 上記で分離した本文(英語原文 Markdown)。
          • raw frontmatter: source_url: <正規化前の原文 URL> / fetched_at / fetched_via: minitools-playwright / tier: B / note: English original scraped via minitools Playwright CDP (verbatim, untranslated)(既存・不変=references/schema.md §3 fetched_via 語彙・verbatim 原則 D2)。日付メタ(Phase 5・Phase 2 で解禁)は emit frontmatter の 4 フィールドを転記する(scrape-medium --emit-meta が JSON-LD datePublished/dateModified を正本に抽出=出所 html-meta。値域 YYYY-MM-DD | unknown・出所 html-meta | unknown=schema §3 と一致)。frontmatter 不在フォールバック時は 4 フィールドとも unknown
        4. exit 1 → stderr を提示し当該 source を中断(Cloudflare ブロック / ログイン切れ / 404 等。raw 未作成・空ページを作らない=既存「取得失敗は中断」規約)。
      • github.com の blob URL → mode F F-4a の gh api 経路に準じる(WebFetch では JS シェルしか返らないため。詳細は §F-4a)。
      • それ以外WebFetch で取得(既存挙動)。
      • mode H(review・会話 URL)が Medium URL を ingest する場合も本 step 3 を通るため 4a routing が自動適用される(対話経路なので Playwright OK)。
    • 日付メタ抽出(Phase 5・経路別・ベストエフォート): raw 保存時、取得経路ごとに元ドキュメント自身の日付を抽出し frontmatter の published_at / last_modified / published_at_source / last_modified_source に記録する(値域・出所 enum は references/schema.md §3「raw フロントマター日付メタ」)。取得不能は当該日付を unknown・対応する *_sourceunknownfetched_at やコンパイル日で代替しない
      • gh api 経路github.com blob): gh api "repos/<owner>/<repo>/commits?path=<path>&sha=<ref>&per_page=1"[0].commit.committer.date(ISO8601)を YYYY-MM-DD に切り詰め last_modifiedgh-commitpublished_at は通常 unknown(CHANGELOG はエントリ日付があるが Phase 5 は commit 日で統一=取りこぼし無し)。
      • WebFetch 経路(一般 URL・blog 含む): まず構造化メタ <meta property="article:published_time">published_at<meta property="article:modified_time">last_modified、無ければ JSON-LD datePublished/dateModified を抽出し出所 html-meta構造化メタが取れない場合は本文可視日付の保守パース(出所 html-body)にフォールバックreferences/schema.md §3「html-body 保守パース規約」=publication-context 限定・曖昧なら unknown・偽日付防止)。claude.com/blogDate: <Month DD, YYYY> 等もこの経路で published_athtml-body として回収する(sitemap に lastmod が無いため)。いずれも取れなければ unknown
      • feed / sitemap 由来(mode I 経由の内部 ingest): mode I I-4 が抽出した日付を ingest にキャリーする(本 step では個別記事を再パースしない)。RSS/Atom の pubDate/updated/published→出所 feed-pubdatepublishedpublished_atupdatedlast_modified)、sitemap の lastmodlast_modifiedsitemap-lastmod
      • Medium 経路(4a): scrape-medium --emit-meta が JSON-LD(datePublished/dateModified)を正本に抽出した日付を出力先頭 frontmatter で受け取りpublished_atlast_modified=出所 html-meta として転記する(上記 step 3 の分離・転記規約を参照)。取得不能フィールドは unknown(Phase 5 の Phase 2・本フェーズで解禁)。
      • 抽出値が日付として parse 不能な場合は unknown に正規化(偽日付を入れない)。抽出失敗は例外にせず続行し wiki/log.mddate extraction: unknown (<raw path>, <route>) を残す。
    • ローカルパス: 既存 raw ファイルとして検証。無ければエラーで中断 (raw は人間が追加するもの。ingest が raw を新規創作しない)。
      • --type=practice 指定時に raw が未存在の場合、raw/notes/ への事前配置を案内して中断 (practice ページの sources: 必須を満たすため)。

3.5. 同一 source 判定(共通 surface・Phase 3d)

raw 保存後・wiki 更新前に、入力 URL(URL 指定の場合)から既存 source ページとの突合を行う。ローカルパス入力の場合は本 step を skip し既存 (iii) 新規 source 作成パスに進む。

URL 正規化(フル仕様・Phase 3e・本節が単一正本): 突合前に URL を次のルールで正規化する。この正規化規約は mode G G-4 / mode H H-3 からも参照される唯一の正本であり、それらの節では再記述しない。適用順:

  1. host を lowercase 化(全 URL に安全)。
  2. fragment 除去#... を削除・全 URL に安全)。
  3. 末尾スラッシュを 1 個まで除去/page//page/ 単独はそのまま)。
  4. tracking param 除去(curated denylist): query string のうち denylist キーのみ除去する。denylist = utm_source / utm_medium / utm_campaign / utm_term / utm_content / fbclid / gclid / ref / ref_src / mc_cid / mc_eid / sourcePhase 4 追加・Medium の ?source=email-... 等 tracking param)。denylist 以外の param(?page=2 / ?id=123 / ?v=xxx 等)は保持する。
  5. host allowlist 正準化(Tier A 4 host・任意): schema §4 の 301 移転元(docs.anthropic.com/en/docs/claude-code/*code.claude.com/docs/en/*docs.anthropic.com/en/api/*platform.claude.com/docs/en/*)は移転先 host に正準化してよい(突合の取りこぼし防止)。

denylist 方式の根拠(strip-all-query 不採用): Phase 3e は任意の Tier B host を dedup 経路に初めて載せる。Tier B には ?page=2 等の意味のある query param が多く、strip-all-query はこれらを畳んで別 URL を同一視し content を silent に取りこぼす。tracking param のみを curated denylist で除去するのが correctness 上の正解。fragment 除去・host lowercase は全 host に安全。

normalize-on-compare(移行不要): raw のフロントマター source_url原文 URL を保持(E1 不変・正規化前)。突合は (i)/(ii) いずれも比較時に両辺を本ルールで正規化して行うため、本正規化を導入しても既存 raw source_url の書き換え(移行)は不要。一方 current-baseline.md.pending_discoveries[].url は正規化済みで格納されるため、mode G G-4 冒頭で一度だけ再正規化する(mode G 側に記載)。

3 段判定: 正規化後の URL を次の優先順で判定する:

優先 判定 アクション
(i) 既存 source ページの最新 raw の source_url と完全一致(双方を正規化して比較)。解決はモード F F-3 step 3〜4 と同じ走査: 各 wiki/sources/*.mdsources: 末尾(YYYY-MM-DD プレフィックス最大)の raw を Read し、その raw のフロントマター source_url を取得する。source ページ自身のフロントマターに source_url は無い(schema §2 共通フィールドに含まれず、source_url は raw のフロントマターキー=schema §3)ため、必ず raw を辿る。source_url を欠く raw は突合対象外。 既存 source ページに統合(step 6 へ。本 raw を sources: 末尾 append、再コンパイル、updated 進行)
(ii) current-baseline.md.migration_pending[].new_url のいずれかと一致 該当エントリの source_slug で示される旧 source ページに統合(新 raw=source_url=new_url を sources: 末尾 append することで F-3 走査が以降 new_url を最新 URL として解決する。source ページ自身に source_url フィールドは無いため書き換え対象は無い)、migration_pending エントリを削除(step 6 / step 9 内で同一 commit)。tier は旧ページの値を継承(再判定しない)
(iii) 上記いずれにも一致しない 新規 source ページを作成(既存挙動・step 6 (a)/(b)/(c) と同じ)

判定結果(i/ii/iii とマッチした既存ページがあれば slug)を以降の step に伝搬する。

  1. 既出チェック

    • wiki/log.md を Grep し同一ソースの既出を確認。既出なら再取り込み可否を AskUserQuestion で確認(強制しない)。
  2. 全文読込・要点確認

    • raw を全文読込し要点を抽出 → ユーザーに要点を提示し AskUserQuestion で確認。
  3. ページ生成/更新(引数による分岐)

    (a) 引数無指定(既存挙動・変更なし):

    • references/schema.md のページタイプ規約・references/page-templates.md の雛形に従い、 source ページ(必須)+関連 concept/entity/comparison を生成/更新する。

    (b) --type=practice:

    • 主たる生成型を practice に切り替え、wiki/practices/<slug>.mdreferences/page-templates.md の practice テンプレで生成する (セクション「試した内容 / 文脈・前提 / 結果 / 結論 / 関連 / 矛盾」)。
    • source ページも併存生成する(raw の要約として wiki/sources/<slug>.md)。 practice は raw に対する「実践と効果の記録」として別ページ。
    • 関連 concept/entity の派生は通常 ingest と同じく必要に応じて生成。

    (c) --feature=<slug>:

    • 通常の source 生成フローを実行(source + 派生 concept/entity)。
    • wiki/features/<slug>.md の存在を確認:
      • 存在しない → references/page-templates.md の feature テンプレで新規作成。
      • 存在する → 「バージョン別仕様差分」セクションに今回 source の知見を追記。 既存記述と矛盾する場合は schema.md §「黙って上書きしない」に従い ## 矛盾 セクションへ。
    • feature ページのフロントマター claude_code_version / updated を新 source の値で更新 (version 進行を反映)。本文の他部分は触らない。
    • バージョン逆行ケース(新 source の claude_code_version が既存 feature ページより古い)は ## 矛盾 セクション追記+AskUserQuestion で続行可否を確認(黙って上書きしない)。

    いずれの分岐でも、フロントマターは references/schema.md §2 の必須フィールドを全て充填する (tier 判定は §4。判定ロジックは Phase 2a だが値の保持は MVP から必須)。 本文に raw 引用と [[wikilink]] を含める(記法は references/schema.md §3)。

    --watch 指定時の watchlist 登録(Phase 3f): 利用者が --watch を指定した場合、生成/更新する source ページのフロントマターに watch: true を立てる(フィールド定義は references/schema.md §2)。これにより mode W(refresh-watchlist)の日次自動再取得対象になる。

    • Medium URL は --watch を reject(Phase 4・D8・§5.3): 入力 host が medium.com / *.medium.com かつ --watch 指定の場合、watch を立てず「Medium は Playwright(scrape-medium --cdp)取得のため watchlist 自動 refresh(mode W = WebFetch 既定経路)に非対応です。最新版は再 ingest してください」と案内して watch 無しで続行する。理由: mode W は WebFetch 既定で mode B step 3 の host routing を通らず Playwright に乗れないため、Medium を watch すると毎晩 Cloudflare/paywall で fail し fetch_status: failed(lint #15)が永続する。この reject は tier: B 判定(下記)より先に評価する。
    • tier: B 専用: 解決した tier が A の場合は watch を立てず、「Tier A は refresh-tier-a(mode F)が既に日次 refresh するため watchlist 登録は不要です」と警告して watch 無しで続行する(黙って立てない・mode F と mode W の二重 refresh を避ける)。
    • 既存 source ページに統合(step 3.5 (i)/(ii))するケースでも --watch 指定なら当該 source ページに watch: true を立てる(後付け登録に相当)。tier は (ii) で旧ページ値を継承するため、その値が A なら上記 tier=A 警告分岐に従う。

    --feed 指定時のフィード登録(Phase 3g): 利用者が --feed=<rss_url> を指定した場合、生成/更新する source ページのフロントマターに feed_url: <rss_url> を立てる(フィールド定義は references/schema.md §2)。これにより mode I(discover-watchlist)の日次フィード巡回対象になる。

    • 既存 source ページに統合(step 3.5 (i)/(ii))するケースでも --feed 指定なら当該 source ページに feed_url を立てる(後付け登録に相当)。
    • --watch との併用可: feed_url(サイト全体の RSS 登録)と watch: true(単一 URL の watchlist 登録)は同一 source ページに共存できる。

    共通 surface 追記事項(Phase 3d・step 3.5 の判定が (i) または (ii) の場合):

    • sources: 末尾 append(F-6・時系列保証): 既存 source ページのフロントマター sources: 末尾に新 raw のパスを append。順序は時系列保証(新しい raw が末尾)。既存 raw は不変保持(E1)で削除・並べ替えしない。
    • (ii) の追加処理: マッチした旧 source ページへ新 raw(フロントマター source_url = new_url・正規化前の原文 URL を保持)を sources: 末尾 append する。これにより F-3 走査(sources: 末尾 raw → その raw の source_url)が以降 new_url を最新 URL として解決する(source ページ自身に source_url フィールドは無いため書き換えは行わない/不要。旧記述「旧 source ページのフロントマター source_url を書き換え」は存在しないフィールドを指していた誤りで Phase 3c carve-out 実機検証で是正)。tier は旧ページの値を継承(不可触)。title 等の手動編集領域は不可触。updated を今日付に進める。
    • (ii) の migration_pending エントリ削除: current-baseline.md.migration_pending[] から該当エントリ(source_slug で特定)を削除する。これは step 9 のコミット内で同一 commit に含める。
      • anchor 戦略: old_string には当該エントリ 4 キー全体( - old_url: ... から source_url: ... まで・前後の \n を含む 5 行)を厳密マッチで指定し replace_all: false。複数エントリがあっても old_url で一意に特定されるため衝突しない。
  4. 矛盾検出(一段目・同一トピックのみ)

    • 新主張が触れる [[wikilink]] 先の既存ページのみを読み、矛盾があれば当該ページに ## 矛盾 セクションを追記し両論併記(黙って上書きしない)。
    • トピック横断の矛盾は MVP では検出しない(Phase 2b lint #5 へ委譲)。
    • 日付補助注記(Phase 5・b1): 新旧両側の出典 raw の last_modified がいずれも unknown 以外なら、## 矛盾 セクションに (last_modified: <旧>→<新>) を併記する(ingest 時は新旧 raw が手元にあるため追加 Read 0)。配置は #11 パーサと衝突しない形に固定: 両論 bullet(- **<ラベル>(<version>・Tier <X>>)**: …)でも 評価: 行でも 決着( 行でもない、- ** で始まらない独立行として追記する(lint #11 は - ** 始まりの行のみ両論候補として解釈するため、本注記は #11 のパース失敗・両論誤検出を引き起こさない=references/lint-rules.md #11 パース仕様)。決着の自動適用はしない(「黙って上書きしない」維持・lint #11 の承認制決着が正経路)。Tier A 優先は不変=日付で公式の権威を覆さない。片側でも unknown なら日付注記を付けない。
  5. Tier B のバージョン乖離提案

    • tier が B(references/schema.md §4)かつ当該知見の前提バージョンが current-baseline.md と乖離する場合、current-baseline.md 更新を AskUserQuestion で承認制提案する(自動更新しない)。

8.5. overview 自動更新(Phase 3d・C)

wiki/overview.md## 現状 セクションを更新する。詳細仕様は references/schema.md §8 参照。

  • 統計取得: Glob('wiki/sources/[!_]*.md') 等で各タイプの 5 ディレクトリ(sources / concepts / syntheses / practices / features)を count(_fixture-* 除外)。
  • 日付: 「最終 ingest」は本日付、「最終更新」も本日付(後段の値変化ガードで差替検査)。
  • 値変化ガード: wiki/overview.md を Read し ## 現状 セクションの現状の 5 件 + 2 日付をパース。すべて同値なら Edit を skip し wiki/log.mdoverview unchanged (<日付>) を 1 行追記、step 9 へ進む。
  • 1 つでも変化があれば: ## 現状 セクション(見出し直後から空行 or 次見出しまで)を Edit で置換し、step 9 のコミットに含める。
  • 境界判定失敗時## 現状 見出しが見つからない): overview Edit を skip し log.md に overview update skipped: section boundary not found (<日付>) を warning 追記。step 9 へ。
  • 更新対象が無い場合: step 6 で source ページ更新なしのケース(dry-run 相当)は overview 更新も skip。
  1. index/log 更新・コミット

    • wiki/index.md に各生成/更新ページの主要主張サマリ(1〜2 行)を維持 (Phase 2 横断矛盾スキャンの前提)。
    • 代表鮮度日の併記(Phase 5・b4): 各生成/更新ページのサマリ行末尾に (鮮度: YYYY-MM-DD) を付す/更新する(畳み込み・最大値の定義は references/schema.md §3「鮮度日(畳み込み)」「index.md 代表鮮度日記法」)。各 raw の鮮度日は last_modifiedunknown 以外ならそれ、不在なら published_at、両方 unknown なら除外unknown は文字列センチネル=null 合体 ?? ではなく明示的に読み飛ばす)。代表値は sources: 全 raw の鮮度日のうち unknown を除いた最大値(全て鮮度日なしなら (鮮度: unknown))。新規 (iii) は当該 raw のみで算出(追加 Read 0)。既存統合 (i)/(ii) は再 ingest で古い記事を足しても鮮度日が後退しないよう、当該ページの sources: raw frontmatter を読んで最大値を取り直す(1 ページ分・bounded・step 6 で読んだ分は再利用)。lint #17 と b3 はこの index トークンを再利用する。
    • wiki/log.md に操作(日時・ソース・生成/更新ページ)を追記。
    • step 6 共通 surface (ii) で current-baseline.md.migration_pending エントリ削除が発生した場合は同一 commit に含める。
    • step 8.5 で overview Edit が発生した場合は同一 commit に含める。
    • 呼び出し元が discover-tier-a(モード G)由来current-baseline.md.pending_discoveries エントリ削除をステージしている場合は、それも同一 commit に含める(モード G G-6 が ingest 本体呼び出し前後にステージする・「ingest と候補削除を同一 commit」契約の担保)。上記 migration_pending / overview と同じく「呼び出しコンテキスト由来の付随ステージ変更を per-source commit に同梱する」一般規約として扱う。
    • ボールト側 Git に操作単位でコミット。
  2. lock 解放(ステップ 0.6 の手順)。例外時も trap 相当で削除を試みる。

--watch 非伝播(Phase 3f・advisor 指摘・誤発火防止)

--watch(watchlist 登録フラグ)は 利用者の直接 /llm-wiki ingest 呼び出しのみで有効。共通 surface(モード B step 3〜9)を内部呼び出しする以下の経路は --watch渡さない=default-off を維持し、discover / 会話 / migration 由来の URL が誤って watchlist 登録されるのを防ぐ:

呼び出し元 経路 --watch
モード G(discover-tier-a) G-6 → mode B ingest 本体 渡さない
モード H(review・会話 URL) H-5 → mode B ingest 本体 渡さない
モード I(discover-watchlist) I-6 → mode B ingest 本体 渡さない
モード F migration(mode L §2.5 migration_pending 提案 / mode B step 0.b 承認後の migration ingest) mode B(migration case) 渡さない

--feed 非伝播(Phase 3g・誤発火防止)

--feed(フィード登録フラグ)も --watch 同様に非伝播とする。共通 surface 内部呼び出し(モード G G-6 / モード H H-5 / モード I I-6 / モード F migration)は --feed を渡さない。mode I の I-6 が mode B を呼ぶときも --feed を渡さない(発見された各記事 URL に feed 登録は不要)。

呼び出し元 経路 --feed
モード G(discover-tier-a) G-6 → mode B ingest 本体 渡さない
モード H(review・会話 URL) H-5 → mode B ingest 本体 渡さない
モード I(discover-watchlist) I-6 → mode B ingest 本体 渡さない
モード F migration mode B(migration case) 渡さない

retrofit(既存 source の後付け登録・Phase 3f)

既に取り込み済みの source ページを後から watchlist に載せたい場合は、当該ページのフロントマターに watch: true手動追記すれば足りる(mode W が次回走査で拾う)。3f では retrofit 専用コマンドを新設しない。ingest 後に毎回 AskUserQuestion で登録可否を問う案は、共通 surface での毎回 prompt・誤発火リスクのため不採用(design D5)。


モード C: /llm-wiki query <質問>

Wiki から引用付きで回答する。読み取り専用(ボールトに書き込まない)。

  1. wiki/index.md を読み、質問に関連するページを特定する。
  2. 関連ページのみを選択読込(全 wiki 走査禁止=コンテキスト圧迫回避)。
  3. 引用付きで回答を統合する(各主張に出典ページ/raw を併記)。
  4. Wiki に不足がある場合は WebSearch/WebFetch で補完し、その箇所を ⚠️ Wiki 外(Web 検索) と明示する。
  5. 補完で有用な未取り込みソースが見つかれば /llm-wiki ingest <url> を提案する (提案のみ。query では取り込まない)。

モード D: /llm-wiki synthesize <テーマ>

テーマ横断の派生成果物(チートシート/Tips 集等)を生成/再生成する。

lock: ステップ 0.5 直後に取得(ステップ 0.6 参照)、最終コミット後に解放する。

  1. lock 取得(ステップ 0.6 の手順)。
  2. wiki/index.md → テーマ関連ページ群を選択読込。
  3. references/page-templates.mdsynthesis 雛形に従い wiki/syntheses/<slug>.md を生成、または既存があれば再生成する。 フロントマターは references/schema.md §2 に従い充填。
  4. すべての項目は元 Wiki ページ/raw を引用する。Wiki 外で補完した箇所は ⚠️ Wiki 外(Web 検索) と明示し、ingest を提案する。 3.4. 鮮度反映(Phase 5・b3): 引用元ページの代表鮮度日(wiki/index.md(鮮度: …) トークンを再利用・無ければ当該ページ sources: raw から算出)を成果物に反映する:
    • 引用元の鮮度日が 180 日超unknown は対象外)の項目には ⚠️ 古い情報(鮮度: <date>) を併記する。
    • 同列の選択肢/手法を列挙する箇所は、鮮度日の新しい順に並べる(unknown は末尾)。 3.5. overview 自動更新(Phase 3d・C): モード B step 8.5 と同じ仕様(references/schema.md §8)。統計 5 件 + 2 日付を計算し wiki/overview.md## 現状 セクションを Read、全値同値なら Edit を skip し log.md に overview unchanged (<日付>) を追記、差分があれば Edit して step 4 のコミットに同梱する。境界判定失敗時は skip + log warning。
  5. wiki/index.md のサマリ更新(synthesis ページ行に代表鮮度日 (鮮度: YYYY-MM-DD) を併記=当該 synthesis の sources: 全 raw の鮮度日の最大値〔unknown 除外・references/schema.md §3 定義〕・モード B step 9 と同仕様)・wiki/log.md 追記・ボールト側 Git コミット(overview Edit が発生していれば同一 commit に含める)。
  6. lock 解放(ステップ 0.6 の手順)。

モード L: /llm-wiki lint [--check=]

Phase 2a 機械判定 7 検査(#1 孤立 / #2 更新日 30 日超 / #3 claude_code_version 乖離 / #4 stale:true 監査 / #6 信頼度 / #7 index 同期 / #9 current-baseline.md 鮮度)に加え、 Phase 2b 意味解釈 4 検査(#5 cross-topic / #8 synthesis-stale / #10 three-way / #11 version-resolve、うち #11 は AskUserQuestion 承認制で ## 矛盾 末尾に決着注記を追記)と、 Phase 3a/3c/3f/3g 機械判定 5 検査(#12 last-tier-a-refresh / #13 last-discover-tier-a-run / #14 last-refresh-watchlist-run / #15 watch-fetch-failed / #16 last-discover-watchlist-run)と Phase 5 機械判定 1 検査(#17 source-date-stale=代表鮮度日 180 日超で情報・index.md 再利用・書き込みなし)を実行する(計 17 検査・詳細は references/lint-rules.md)。

書き込みは wiki/log.md への結果サマリ追記+ #11 承認時のみ ## 矛盾 末尾 1 行追記のみ。 本文・フロントマター・index.md への自動補完は一切しない(不変条件「黙って上書きしない」)。

lock 扱い(design.md §6 carve-out): 通常 lint(17 検査レポート+ log.md 追記まで)は lock を 取得しない(log.md は append-only で refresh と並行しても順序問題のみ・実害なし)。#11 承認制決着の ## 矛盾 編集部分のみステップ 0.6 の lock を取得し書き込み完了後に解放する。

書き込み副作用境界(17 検査 × 書き込み有無 × lock)

# id 書き込み lock
1 orphan なし(対話レポート+log.md 集計のみ) 不要
2 updated なし 不要
3 version なし 不要
4 stale なし 不要
5 cross-topic なし 不要
6 confidence なし 不要
7 index なし 不要
8 synthesis-stale なし(detail に手動再生成コマンドを併記) 不要
9 baseline なし 不要
10 three-way なし 不要
11 version-resolve 承認時のみ 該当ページ ## 矛盾 末尾に 1 行追記+ log.md に決着行追記 取得(決着適用部分のみ)
12 last-tier-a-refresh なし 不要
13 last-discover-tier-a-run なし 不要
14 last-refresh-watchlist-run なし 不要
15 watch-fetch-failed なし 不要
16 last-discover-watchlist-run なし 不要
17 source-date-stale なし 不要

検査項目の判定ロジック・しきい値・走査戦略・## 矛盾 パース仕様・決着注記の正規記法は references/lint-rules.md を参照(SKILL.md では再記述しない)。

  1. 引数パース

    • 第 2 トークン以降から --check=<csv> を抽出。<csv>orphan|updated|version|stale|confidence|index|baseline|cross-topic|synthesis-stale|three-way|version-resolve|last-tier-a-refresh|last-discover-tier-a-run|last-refresh-watchlist-run|watch-fetch-failed|last-discover-watchlist-run|source-date-stale のサブセット(カンマ区切り)。
    • 未指定なら全 17 検査。未知キーはエラーで中断し、上記 17 キー一覧を案内。
  2. ステップ 0.5 ボールト前提チェックを継承(init 以外と同じ手順)。ステップ 0.6 lock は通常 lint では取得しない(design.md §6 carve-out)。

2.5. migration_pending 提案(書き込み前・通常 lint 検査群の手前。Phase 3d 共通 surface 経由に再定義):

  • Read("./wiki-vault/wiki/current-baseline.md") でフロントマター migration_pending を取得(後続の走査で再利用するためメモリ保持)。
  • 配列が空なら通常検査群(ステップ 3)に進む。非空なら以下の AskUserQuestion を起動:
    • question: 「Tier A docs ホスト移転を承認しますか?」
    • options: 各 migration_pending エントリ 1 件ごとに <source_slug>: <old_url> → <new_url> ラベル、および**「適用しない」を必ず併置**(候補 1 件のときも・Phase 2b 振り返り由来)。
    • multiSelect: true、候補 5 件超は detected_on 古い順で上位 4 件に絞り、残りは次回提示。
  • 承認分の処理(Phase 3d 共通 surface 経由・旧仕様「URL 書き換え単独」は廃止):
    • (i) 承認された各エントリの new_urlモード B(ingest)の共通 surface に渡して新規 raw を ingest する。モード B step 3.5 の同一 source 判定 (ii) が migration_pending[].new_url 一致を検出し、旧 source ページに統合(新 raw=source_url=new_url を sources: 末尾 append することで F-3 走査が以降 new_url を最新 URL として解決する=source ページ自身に source_url フィールドは無いため書き換えは不要、再コンパイル、updated 進行、tier 不可触、title 等の手動編集領域は不可触)+当該 migration_pending エントリ削除(モード B step 6 内・anchor 戦略はモード B 内に記載)+ 1 commit が成立する。
    • (ii) 当該 raw の source_url は変更しない(raw 不変条件 E1)。旧 raw(old_url 由来)は不変保持され、新 raw のみ追加される。
    • (iii) モード B が .llm-wiki.lock の取得・解放を自身で行うため、本サブステップで lock 取得は不要。モード B が 1 ソース 1 commit を chore: migrate source_url <slug> <old>→<new> 相当のメッセージで作成する(共通 surface (ii) ケース判定の commit メッセージはモード B 内で決まる)。
  • 0 件選択は何もせず通常検査群へ進む。
  1. 走査references/lint-rules.md §走査戦略の通り)

    • Glob("wiki/{sources,concepts,entities,comparisons,syntheses,practices,features}/*.md") で全ページ列挙(1 回)。
    • 各ページを Read(offset=0, limit=50) でフロントマター部分のみ取得(本文不読)。 集約マップに sources / links を含める(#8 用)。
    • Read("wiki/index.md")(1 回・サマリ行と [[wikilink]] を抽出)。
    • Read("wiki/current-baseline.md")(1 回)。
    • Phase 2b 追加 Read--check で対象検査が含まれる場合のみ):
      • #10 用: Read("CLAUDE.md") / Read(".claude/skills/llm-wiki/SKILL.md") / Read(".claude/skills/llm-wiki/references/schema.md") を 1 回ずつ(CWD 起点)。
      • #11 用: Bash("grep -l '^## 矛盾' wiki/{sources,concepts,entities,comparisons,syntheses,practices,features}/*.md")## 矛盾 保持ページを抽出 → ヒットページのみ該当セクションを限定 Read (Read(offset=<セクション開始行>, limit=80) 程度)。全ページ本文 Read はしない
      • #12 用: 既存の current-baseline.md Read を再利用する(追加 Read 0 回)。
      • #13 用: 同じく既存の current-baseline.md Read を再利用する(追加 Read 0 回・last_discover_tier_a_run フィールドを参照)。
      • #14 用: 同じく既存の current-baseline.md Read を再利用する(追加 Read 0 回・last_refresh_watchlist_run フィールドを参照)。
      • #15 用: Phase 2a step 2 の全ページ frontmatter 集約マップ(fetch_status フィールド)を再利用する(追加 Read 0 回)。
      • #16 用: 同じく既存の current-baseline.md Read を再利用する(追加 Read 0 回・last_discover_watchlist_run フィールドを参照)。
    • 以上のデータをメモリ上の集約マップに保持し、以降は追加 Read を行わない。
  2. 検査実行

    • references/lint-rules.md の判定ロジック節(Phase 2a 7 検査 + Phase 2b 4 検査 + Phase 3a #12 + Phase 3c #13 + Phase 3f #14/#15 + Phase 3g #16)に従い、 --check で指定された検査を実行。severity は「要対応 / 警告 / 情報」の 3 段。
    • #5 / #8 / #10 / #12 / #13 / #14 / #15 / #16 はレポートのみ
    • #11 は候補検出後にステップ 8 の承認制 UX を起動(書き込みは承認後のみ)。
  3. 対話出力

    • Markdown 表(カラム: file / check / severity / detail)で全 17 検査の結果を統合出力。
  4. wiki/log.md 追記

    • ### lint 結果(YYYY-MM-DD HH:MM) セクションを追記。
    • severity 別集計(要対応 N / 警告 M / 情報 K)と検査別件数を 1 行ずつ記録: 検査別件数: orphan=A, updated=B, version=C, stale=D, confidence=E, index=F, baseline=G, cross-topic=H, synthesis-stale=I, three-way=J, version-resolve=K, last-tier-a-refresh=L, last-discover-tier-a-run=M, last-refresh-watchlist-run=N, watch-fetch-failed=O, last-discover-watchlist-run=P
    • 全件詳細は対話のみ(log.md 肥大化防止)。
  5. レポートコミット

    • ボールト Git で wiki/log.md の差分のみを git addchore: llm-wiki lint (YYYY-MM-DD) でコミット。
    • lint は他のファイルを変更しないため、log.md 以外の差分は発生しない。 もし発生していたら不変条件違反としてユーザーに報告し中断(自動書き込みの取り残し検知)。
  6. #11 承認制 UX(候補が 1 件以上ある場合のみ)

    ステップ 5–7 の検査全件レポート出力+レポートコミットに起動する。

    overview 更新なし(Phase 3d): 本サブステップは ## 矛盾 末尾 1 行追記+ log.md 決着行追記のみで、wiki/overview.md は不可触(source ページ統計に変化なしのため。references/schema.md §8.4 更新タイミング表参照)。書き込みモードであっても overview 自動更新は走らない。

    1. 候補の選別: #11 の時系列 supersession 候補をリスト化する。5 件超なら上位 4 件のみ提示 (AskUserQuestion の選択肢上限 4 件)。ソート順: severity 高い順(要対応 > 情報)→ version 差大きい順 (major 桁差 > minor 桁差)。残りは対話レポートに「次回 lint で再検出可」と明示。
    2. AskUserQuestion を起動:
      • question: 「次の N 件に決着注記を追記しますか?(適用したいページを選択。何も選ばなければ追記なしで終了)」
      • options: 候補ページごとに 1 件、ラベル形式は <slug> (v_old=X Tier B → v_new=Y Tier A)
      • multiSelect: true
      • 「いずれも適用しない」専用オプションは置かない(0 件選択がそのまま「適用しない」を意味する)
    3. 選択 0 件 → 追記なし・コミットなしで終了。候補は対話レポートに残る。
    4. 選択ページごとの末尾アンカー手順: a. 該当ページの ## 矛盾 セクション末尾を Read で確認(既に限定 Read 済みデータを使用可)。 b. 既に決着行(references/lint-rules.md §「#11 決着注記の正規記法」の二重追記回避規約)が セクション内にあればスキップ。 c. セクション末尾の最終非空行を取得し、Edit で
      • old_string = 最終非空行(そのまま)
      • new_string = 最終非空行 + \n + 決着行(記法は references/lint-rules.md §「#11 決着注記の正規記法」の正規記法に従う。SKILL.md では再記述しない)
      • replace_all: false 厳守 d. wiki/log.md のサマリ直下に決着行を 1 行追記する(記法は references/lint-rules.md §「#11 決着適用時の log.md 追記フォーマット」を参照)。
    5. 決着適用コミット: 追記が 1 件以上発生したらボールト Git で chore: llm-wiki lint resolve (YYYY-MM-DD) でコミット(## 矛盾 編集と log.md 追記をまとめる)。 レポートコミット(ステップ 7)とは分離する。

エラーハンドリング(lint)

references/lint-rules.md §エラーハンドリング表(Phase 2a/2b 共通+ Phase 2b 追加)を参照 (再記述しない)。要点:

事象 扱い
--check 未知キー 中断し 17 キー一覧を案内
フロントマター YAML パース失敗 該当ページのみ「要対応: フロントマター不正」表示し他検査継続
sources: 「要対応: sources 空(schema.md §2 違反)」表示
current-baseline.md 不在 #3/#9/#12 をスキップ
ボールト未コミット変更あり AskUserQuestion で続行可否
## 矛盾 セクション構造不正(grep ヒットだが Read で該当行なし) 「要対応: ## 矛盾 セクション構造不正」表示、他検査継続
#10 で本リポジトリ側 3 文書のいずれかが Read 不能 #10 をスキップし要対応表示
#11 候補ページが Read できない 該当候補のみスキップ、他候補は続行
AskUserQuestion で 0 件選択 追記なし・コミットなしで終了
#11 候補が 5 件超 上位 4 件のみ承認確認、残りは次回 lint で再検出
## 矛盾 末尾に既に「決着(」行がある 二重追記を回避してスキップ
#8 で synthesis の sources: が空 Phase 2a sources: 空エラー扱いに委ね、#8 はスキップ
#12 last_tier_a_refresh 未設定 / parse 不能 要対応として個別レポート、他検査継続(詳細は references/lint-rules.md §Phase 3a 追加)
migration_pending が YAML として parse 不能 「要対応: current-baseline.md の migration_pending 破損」を表示し、本フローはスキップして通常検査群へ進む

モード F: /llm-wiki refresh-tier-a [--dry-run]

Tier A(公式 docs / 公式 GitHub)ソースの日次自動再取得を行う非対話モード。launchd / cron から claude --print '/llm-wiki refresh-tier-a' --allowedTools=Read,Write,Edit,Bash,Grep,Glob,WebFetch 形式で起動される。AskUserQuestion は一切起動しない(対話シェルから force-run でも同じコードパス)。

lock: ステップ F-1 で取得、ステップ F-7 で解放。

F-1. lock 取得

ステップ 0.6 の atomic 取得手順に従い mode: refresh-tier-a で取得。失敗時は wiki/log.mdrefresh-tier-a: locked, skipped (YYYY-MM-DD) を 1 行追記し exit 0。スタール判定で奪取した場合は refresh-tier-a: stale lock recovered (pid=X, started=Y) を追記してから F-2 へ進む。

F-2. vault dirty-state チェック

Bash("git -C ./wiki-vault status --porcelain -- ':!wiki/log.md'") の出力が非空なら、wiki/log.mdrefresh-tier-a: vault dirty, skipped (YYYY-MM-DD) を追記、log.md だけの 1 commit chore: log refresh-tier-a skipped (dirty) を作成し、lock を解放して終了(stash / 自動 commit 禁止)。

Phase 3d(F-3)修正: 判定式は git pathspec :!wiki/log.mdwiki/log.md のみを除外する。log.md は schema.md §3「log.md dirty 状態 append 規約」で agent 完全所有・追記のみと規定されており、dirty 状態でも append + commit 可。これにより skip 時の log append commit が成功し、dirty escalation ループ(log.md 追記が次回 refresh で dirty 検知して skip → さらに append → …)が解消される。grep -v 'wiki/log.md' ベース実装は wiki/log.md.bak 等の false negative を生むため pathspec exclusion を採用する。

F-3 と F-4 の独立論点訂正(2026-05-24 brainstorm の旧フレーミングを 2026-05-29 brainstorm で訂正): F-3 は cron dirty escalation の特殊事象(本 F-2 で単独解消)、F-4 は通常 ingest と同じ append 規約(モード B 共通 surface で扱う)。両者は独立論点であり「同じ log.md append 規約として束ねる」旧フレーミングは廃止。

F-3. 対象 Tier A ソース集合の決定

references/schema.md §2.1 / §3 の規約に従って次の手順で機械的に決める(シードリスト/別途のクロール設定は持たない):

  1. Glob('./wiki-vault/wiki/sources/*.md') でページ列挙、各ページを Read(offset=0, limit=50) でフロントマター取得。
  2. フロントマター tier: A のページのみ候補。
  3. 各候補ページの sources: 末尾(ファイル名プレフィックス YYYY-MM-DD が最大のもの)を最新 raw として解決。
  4. 当該 raw のフロントマター source_url を取得。source_url が無い/tier: A でない raw は skip+log (refresh-tier-a: no source_url <slug>)
  5. 結果は (source_slug, latest_raw_path, source_url) の三つ組リスト(source_slug の ASCII 昇順で決定論的に並べる)。
  6. 孤立 raw(対応する source ページが無い)は対象外。lint #1 と責務分離。

F-4. per-source ループ

各三つ組について以下を順に実行(失敗ソースは skip+log し commit せず次へ・git push しない):

F-4a. 取得(経路 routing):

  • source_urlhttps://github.com/{owner}/{repo}/blob/{ref}/{path} パターンにマッチする場合は gh api 経路 を使う(WebFetch では JS レンダリング前の HTML シェルしか返らず本文取得不能なため):
    • Bash('gh api "repos/{owner}/{repo}/contents/{path}?ref={ref}" --jq .content | base64 -d') を実行。{ref} はブランチ名/タグ名/sha のいずれでもよい。
    • 取得経路フラグ fetch_method = gh-api を立て、F-4c のフロントマター生成に伝搬する。
    • 失敗時はそのソースを skip し wiki/log.mdfail <slug>: <error> 行を追記、次のソースへ(gh CLI 未インストール/gh auth 切れ/404 などはエラーハンドリング表参照)。
  • それ以外の URL は WebFetch 経路:
    • WebFetch(source_url, "<取得テキスト全文を要約せず可能な限り原文に近い形で抽出>") を試行。
    • 取得経路フラグ fetch_method = webfetch を立てる。
    • 失敗時はそのソースを skip し wiki/log.mdfail <slug>: <error> 行を追記、次のソースへ。

F-4b. 301 リダイレクト検出(WebFetch 経路のみ発火・gh api 経路では skip):

  • 取得結果のメタが redirect を示す or status が 301 の場合:
    • current-baseline.md フロントマター migration_pending を Read。
    • 当該 source_slug のエントリが既に存在すれば skip+ log (suppressed: pending migration <slug>)。再 append しない。
    • 存在しなければ migration_pending に 1 エントリ append: {old_url: source_url, new_url: <リダイレクト先>, detected_on: <今日>, source_slug: <slug>}
    • current-baseline.md を 1 commit refresh(tier-a): migration_pending append <slug>
    • 当該ソースの本文再コンパイルは行わず次のソースへ(古い URL のままで運用継続)。

F-4c. 通常取得成功時の raw 追加保存:

  • 保存先: raw/<種別>/<取得日 YYYY-MM-DD>-<slug>.md(種別は raw の既存配置に揃える。docs / articles / github 等)。
  • 既存ファイル上書き禁止(E1 不変条件)。同日 2 回目以降は末尾に -2, -3, ... の連番を付与:
    • Bash('ls ./wiki-vault/raw/<種別>/<取得日>-<slug>*.md 2>/dev/null | wc -l') で件数を取得し、N>0 なら <slug>-(N+1) を使う。
  • フロントマター: source_url / fetched_at / tier: A を必ず記録。fetched_vianote は F-4a の取得経路で分岐:
    • fetch_method = webfetch の場合: fetched_via: WebFetch / note: WebFetch 要約(逐語性ポリシーは memory/webfetch-raw-snapshot-policy.md 参照)
    • fetch_method = gh-api の場合: fetched_via: "gh api repos/{owner}/{repo}/contents/{path}?ref={ref} (verbatim / 逐語コピー)" / note: "原文逐語スナップショット(gh api 経由で base64 デコード)。要約ではない。再検証は source_url を参照。"
  • 日付メタ(Phase 5・経路別・ベストエフォート): frontmatter に published_at / last_modified / published_at_source / last_modified_source を記録(references/schema.md §3)。
    • fetch_method = gh-api: Bash('gh api "repos/{owner}/{repo}/commits?path={path}&sha={ref}&per_page=1" --jq ".[0].commit.committer.date"') の ISO8601 を YYYY-MM-DD に切り詰め last_modifiedgh-commitpublished_atunknown
    • fetch_method = webfetch: 構造化メタ article:modified_time/article:published_time・JSON-LD dateModified/datePublished を抽出し html-meta、取れなければ本文可視日付の保守パース → html-body(schema §3 規約)。Tier A docs(code.claude.com 等)の .md 逐語はメタも publication-context 本文日付も持たないことが多く、その場合は unknown(偽日付を入れない・dry-run 実証)。
    • 取れない/parse 不能は unknown。失敗は例外にせず log date extraction: unknown (<raw path>, <route>)

F-4d. 差分判定:

  • 新 raw の fetched_at > 該当 wiki/sources/<slug>.mdupdated なら F-4e 再コンパイルへ進む。
  • 等しい/古い場合は raw 追加のみで wiki 更新スキップ。wiki/log.mdunchanged <slug> を追記。

F-4e. 再コンパイル:

  • 既存 ingest(モード B)と同じ「同一トピック [[wikilink]] 先のみ照合・矛盾は ## 矛盾 追記」の経路を踏襲。横断矛盾は lint #5 委譲。
  • wiki/sources/<slug>.md のフロントマター claude_code_version / updated を新 raw の値で更新。
  • sources: 末尾 append(F-6・時系列保証): 新 raw のパスを wiki/sources/<slug>.md のフロントマター sources: 末尾に append(モード B step 6 共通 surface 追記事項と同じ仕様)。既存 raw は不変保持で削除・並べ替えしない。
  • 本文は最小改変(要約差分の反映のみ)。confidence は維持(既存値を尊重)。
  • 代表鮮度日の更新(Phase 5・b4): 新 raw の日付メタで当該ページの代表鮮度日(sources: 全 raw の鮮度日の最大値〔unknown 除外・references/schema.md §3 定義〕)が進む場合、wiki/index.md の当該行の (鮮度: YYYY-MM-DD) を更新(モード B step 9 と同仕様・per-source commit に同梱)。

F-4f. current-baseline.md の baseline フィールド更新:

  • 当該ページに claude_code_version 更新が含まれていれば current-baseline.mdclaude_code_version / updated を更新。
  • schema_version / schema_repo_commit / schema_summary は不可触(schema 軽量ポインタは co-evolution 経路のみ)。

F-4g. overview 自動更新(Phase 3d・C):

  • モード B step 8.5 と同じ仕様(references/schema.md §8)。
  • 統計 5 件 + 2 日付を計算し wiki/overview.md## 現状 セクションを Read。全値同値なら Edit を skip し log.md に overview unchanged (<日付>) を 1 行追記。1 つでも差分があれば Edit。
  • 境界判定失敗時は skip + log warning。--dry-run では Edit / commit せず would-update overview <fields> をレポート。

F-4h. per-source commit:

  • ボールト側 Git で当該ソース関連の差分(raw 追加・wiki/sources/.md 更新・overview 更新があれば含む)のみを git add し、refresh(tier-a): <slug> at <取得日> でコミット。
  • git push しない

F-5. 全ソース処理後の last_tier_a_refresh 更新

  • current-baseline.md フロントマターの現在の last_tier_a_refresh を Read。
  • 値が本日付と等しい場合(同日 2 回目以降の force-run): Edit / commit をスキップし、wiki/log.mdlast_tier_a_refresh unchanged (<date>) を 1 行追記して F-6 へ進む(空 commit ガード)。
  • 値が本日付と異なる場合: フロントマターを本日付に Edit。さらに overview 自動更新を inline で実行(モード B step 8.5 と同じ仕様・値変化ガード付き)。両編集を 1 commit refresh(tier-a): last_tier_a_refresh = <date> に同梱する(F-4g の per-source commit が既に overview 値を最新化している可能性があるため、F-5 では値変化ガードで skip されるのが典型ケース)。
  • --dry-run モードではいずれの分岐も commit を行わず、would-update last_tier_a_refresh <old> -> <today> または last_tier_a_refresh unchanged (<date>) を標準出力にレポートするのみ(overview の差分予測も含める)。

F-6. サマリ追記

  • wiki/log.md に 1 行 refresh-tier-a: ok=N skip=M fail=K (YYYY-MM-DD) を追記。
  • 1 commit chore: log refresh-tier-a summary

F-7. lock 解放

ステップ 0.6 の解放手順に従う。例外時も trap 相当で削除を試みる。

--dry-run モード

  • F-1(lock 取得)/ F-2(dirty-state)/ F-3(対象集合決定)を実行。
  • F-4 ループは per-source の判定結果unchanged / would-update / would-append-migration-pending / fail 予測)を標準出力にレポートするのみ。
  • raw 追加・wiki 更新・current-baseline 更新・git commit を一切行わない
  • F-5 / F-6 の commit も行わない。
  • F-7 lock 解放のみ実行(dry-run でも並行実行禁止)。

モード F のエラーハンドリング

事象 扱い
.llm-wiki.lock を他プロセスが取得済み(生存中) F-1 で skip log を追記して終了
.llm-wiki.lock がスタール(1h 経過+kill -0 fail) 強制奪取し stale lock recovered ログ追記して通常実行
vault dirty F-2 で vault dirty, skipped ログ追記して終了(lock 解放)
WebFetch 失敗(個別ソース) F-4a で当該ソース skip、log に fail <slug>: <error>
gh: command not found(gh CLI 未インストール) F-4a gh api 経路で当該ソース skip、log に fail <slug>: gh CLI not installed 行。launchd EnvironmentVariablesPATHgh を含めるよう案内
gh auth status 失敗(認証切れ/token 失効) F-4a gh api 経路で当該ソース skip、log に fail <slug>: gh auth required 行。次回 refresh 前に対話セッションで gh auth login
gh api が 404(ref/path 不在・リポジトリ rename) F-4a gh api 経路で当該ソース skip、log に fail <slug>: gh api 404 <ref>/<path> 行。連続 fail の場合は手動で source ページの sources: 末尾の source_url を新パスへ更新
301 リダイレクト(WebFetch 経路のみ) F-4b で migration_pending append(既出はサプレッション)、当該ソース再コンパイルなし。gh api 経路では F-4b 自体が発火しない
同日 raw 衝突 F-4c で -2, -3, ... 連番付与(既存上書き禁止)
last_tier_a_refresh 既に本日付(同日 2 回目以降の force-run) F-5 で Edit / commit を skip し log に last_tier_a_refresh unchanged (<date>) を 1 行追記して F-6 へ(空 commit ガード)
再コンパイル中の wikilink 解決例外 当該ソース skip し log に recompile fail <slug>
current-baseline.md Read 失敗(破損) 全実行中止し log に baseline unreadable, aborted 追記、lock 解放
migration_pending YAML 破損 current-baseline.md Read 失敗扱いに準じる

対象規模・recurring cost

想定対象は Tier A 主要 docs +公式 GitHub リリースで一桁〜十数件。日次 WebFetch 10〜15 リクエスト/日。 Phase 3a では per-source の weekly/daily 切替は実装しない。


モード G: /llm-wiki discover-tier-a [--no-prompt|--dry-run]

Tier A 公式 docs / 公式 GitHub の未取り込み URL を自動発見し、current-baseline.mdpending_discoveries[] に登録、承認制で共通 surface(モード B)経由 ingest する。手動 ingest の初期登録コストを下げるのが目的(Phase 3c)。

discovery scope = α 厳格(CLI 中心):

  • docs: https://code.claude.com/docs/en/*(英語のみ・agent-sdk/* 含む。翻訳版 11 言語は除外)
  • GitHub: anthropics/claude-code repo ルートの CHANGELOG.md + README.md(repo に docs/ は存在しない=公式 docs は code.claude.com に移管済。plugins/** / examples/** は本 phase 対象外)
  • β/γ scopeplatform.claude.com/docs/en/api/* 1422 URL・Agent SDK 別 repo 等)は本 phase 対象外。手動 ingest 経路で対応。

discovery scope ≠ refresh scope(Y 案): discover-tier-a は発見 + 候補リスト化 + 承認制 ingest のみ。refresh-tier-a(モード F)の §F-3 対象集合は不可触。発見 URL は承認 → モード B ingest → wiki/sources/<slug>.md 作成 → §F-3 の対象集合決定で初めて refresh 対象になる。この順序で Phase 3a の cost assumption(日次 10〜15 req)は崩れない。

実行モード:

モード フラグ 動作 想定起動元
既定(対話) なし discovery → append → AskUserQuestion 承認 → 共通 surface ingest 対話シェル
非対話 --no-prompt discovery → append のみ。AskUserQuestion 不発火・ingest なし launchd / cron
dry-run --dry-run discovery レポートのみ。pending_discoveries / last_discover_tier_a_run 更新も skip・副作用ゼロ 対話シェル(preview)

--no-prompt--dry-run は併用可(discovery 結果のみレポート・副作用ゼロ)。

lock: ステップ G-1 で取得、ステップ G-8 で解放。ingest 中も mode G が lock を保持し続ける(G-6 はモード B の ingest 本体 step 3〜9 のみを呼び、モード B の step 0 lock 取得 / step 10 lock 解放は呼ばない=lock 再入防止)。

G-1. lock 取得

ステップ 0.6 の atomic 取得手順に従い mode: discover-tier-a で取得。失敗時は wiki/log.mddiscover-tier-a: locked, skipped (YYYY-MM-DD) を 1 行追記し終了。スタール判定で奪取した場合は discover-tier-a: stale lock recovered (pid=X, started=Y) を追記してから G-2 へ。

G-2. vault dirty-state チェック

モード F の F-2 と同じ判定式 Bash("git -C ./wiki-vault status --porcelain -- ':!wiki/log.md'") を使う(log.md は agent 完全所有・追記のみのため除外)。出力が非空なら wiki/log.mddiscover-tier-a: vault dirty, skipped (YYYY-MM-DD) を追記、log.md だけの 1 commit を作成し、lock を解放して終了(stash / 自動 commit 禁止)。

G-3. discovery(sitemap + gh api fetch)

  • docs: Bash("curl -sL --max-time 30 https://code.claude.com/sitemap.xml") で sitemap XML を取得し、<loc> タグを抽出して https://code.claude.com/docs/en/ で始まる URL のみフィルタ(翻訳版除外)。WebFetch は sitemap.xml を要約してしまうため使わない(curl で逐語取得)。
  • GitHub: Bash("gh api repos/anthropics/claude-code/git/trees/main?recursive=1 --jq '.tree[] | select(.type==\"blob\") | .path'") で全 path を列挙し、repo ルートの CHANGELOG.mdREADME.md のみ抽出(docs/ は repo に存在しないため対象外・plugins/** / examples/** / .claude/** は除外)。URL 化規約は https://github.com/anthropics/claude-code/blob/main/{path}main 決め打ち)。
  • いずれかの経路が失敗しても他経路は続行(gh api 失敗でも docs 側は続行・エラーハンドリング表参照)。
  • キャッシュは持たない(起動の度に毎回 fetch・α scope は docs 142 + GitHub 2 件で recurring cost は許容範囲)。

G-4. 突合 + 正規化

  • URL 正規化規約は モード B step 3.5(フル仕様・単一正本)を参照(host lowercase + fragment 除去 + 末尾スラッシュ除去 + tracking param denylist 除去 + Tier A host allowlist 正準化)。本節では再記述しない。
  • pending_discoveries[].url 再正規化 migration(Phase 3e・idempotent): 既存 pending_discoveries[].url は旧最小正規化(host lowercase + 末尾スラッシュのみ)で格納されている可能性がある。本 step 冒頭で各 url をフル正規化し直し、変化したものがあれば current-baseline.md を Edit(再正規化済み=変化なしなら no-op)。これにより以降の dedup(正規化後 url キー)が phantom duplicate を生まない。--dry-run では Edit せず would-renormalize <old> -> <new> をレポート。再正規化で Edit が発生した場合は、新規 append 件数 N=0 でも必ず commit するchore: discover-tier-a: renormalize pending_discoveries (YYYY-MM-DD)・G-5 で N>0 の append commit が立つ場合はそれに同梱可)。commit しないと未コミット Edit が vault dirty を生み、次回 refresh/discover が F-2/G-2 dirty-check で skip する。なお Tier A の docs/github URL は utm/fbclid/fragment を持つことが稀のため、本 migration は通常 no-op(低頻度)。
  • 既存 Glob("./wiki-vault/wiki/sources/*.md") の各 source ページについて、モード F F-3 step 1〜4 と同じ走査で既存 URL を解決する: 各ページのフロントマター sources: 末尾(YYYY-MM-DD プレフィックス最大)の raw を Read し、その raw のフロントマター source_url を取得して既存 URL 集合に入れる。source_url を欠く raw は skip。source ページ自身のフロントマターに source_url は無い(schema §2 共通フィールドに含まれず、source_url は raw のフロントマターキー=schema §3)ため、source ページから直接読まず必ず raw を辿る(旧記述「各ページ source_url(フロントマター)を収集」は誤りで、Phase 3c carve-out 実機検証で既存集合が空になり取り込み済み URL が誤って再候補化するバグを修正)。
  • current-baseline.md.pending_discoveries[]current-baseline.md.migration_pending[].new_url を Read。
  • 発見 URL をフル正規化し、次のいずれかに含まれるものを除外 → 未取り込み候補集合。すべて正規化後に突合する:
    • 既存 source_url(取り込み済み)
    • migration_pending[].new_url(移転保留)
    • pending_discoveries[] のうち declined: true のエントリの url(既知の却下=再候補化しない・Phase 3e stuck candidates 対策・§G-6 / schema §2.1 参照)

G-5. pending_discoveries append(dedup ルール)

  • current-baseline.md.pending_discoveries[] を Read。
  • 未取り込み候補のうち、既存 pending_discoveries[].url(正規化後)に含まれないもののみ append(dedup キー = 正規化後 url)。
  • 既存エントリありなら append skipdetected_on は古い方を保持=最初に発見した日付)。これにより cron で日次 --no-prompt 起動しても sitemap 不変なら 1 度 append すれば以後は no-op となり、リスト爆発を防ぐ
  • エントリ形式: {url: <正規化後 URL>, source_kind: docs|github, detected_on: <今日>}references/schema.md §2.1)。
  • append 後の配列で current-baseline.md を Edit。
  • --no-prompt の場合: ここまでで 1 commit chore: discover-tier-a: N new candidates (YYYY-MM-DD) に集約(per-URL commit にしない・migration_pending append 流儀と整合)。その後 G-7 へ(G-6 の ingest は skip)。
  • --dry-run の場合: Edit / commit せず would-append <url> を標準出力にレポート。

G-6. 共通 surface ingest(既定モードのみ・Phase 3e: capped バッチ opt-out)

--no-prompt / --dry-run では本ステップを skip。

承認モデル(Phase 3e amendment): Tier A 公式 docs は信頼ソースのため、利用者の手間を減らすべく opt-out(既定取り込み・除外を選択) とする。ただし 142 件規模の無人一気 ingest を避けるため 1 run あたり ingest 上限 N(既定 20) の機械的ペース制限を置く(人間ゲートではない)。AskUserQuestion は opt-in 仕様(選択 = 対象)のため「除外する候補を選択」と反転提示する。空 submit と dialog 中止が同一の「未回答」結果になり opt-out の『0 件選択=全件取り込み』が判別不能なため、各バッチに sentinel ✅ 全件取り込む(除外なし) を必ず併置し、全件取り込みの意思を明示できるようにする(未回答は安全側で「確定しない」扱い・下記 step 2.2/2.3)。

  1. 候補抽出: pending_discoveries[] から declined: true を除いたエントリを detected_on ASC → URL ASCII 昇順 fallback で並べ、先頭 min(N, 残数) 件を本 run の処理対象とする(N = per-run cap・既定 20)。
  2. ラウンド処理AskUserQuestion の選択肢上限 4 件のうち sentinel「全件取り込む(除外なし)」が毎バッチ 1 枠を占有するため、対象を 3 件ずつのバッチに分割し、最大 ⌈N/3⌉ ラウンド繰り返す)。各ラウンド:
    1. 遅延概要取得: 当該バッチの最大 3 件のみ WebFetch(url, "<タイトルと要旨を 1〜2 文で。要約>") で軽量に概要を取得(取得失敗時は概要なし=url のみ)。全 142 件の先取りはしない(コスト集中回避・idea.md「discover 時先取り」からの逸脱は design §5.2 に記録)。
    2. AskUserQuestionmultiSelect: true)で提示:
      • question: 「取り込みたくない候補を選択してください(選択 = 除外)。すべて取り込むなら『全件取り込む(除外なし)』を選択。何も選ばず submit / ダイアログ中止は『今回は確定しない』扱いで候補は次回 run に残ります」
      • options: バッチの各候補(最大 3 件)ごとに <source_kind>: <概要 or url> ラベル(選択 = 除外)+ 末尾に sentinel ✅ 全件取り込む(除外なし) を必ず併置(合計最大 4 選択肢)。sentinel を常設することで「除外なしで全件取り込む」意思を明示でき、AskUserQuestion空 submit と dialog 中止を同一の「未回答」結果として返す制約(opt-out の『0 件選択=全件取り込み』が判別不能)を回避する。
    3. 選択の解釈(precedence):
      • sentinel のみ選択 → バッチ全候補を取り込む(除外 0)。
      • 個別候補が 1 件以上選択(sentinel 併選を含む)→ 選択された個別候補を除外指定として扱い、sentinel 選択は無視する(個別除外が優先)。残りの候補を取り込む。
      • 未回答(空 submit / dialog 中止) → 本バッチは確定せず ingest も declined 化もしない。候補は pending_discoveries[] に残置し次回 run で再提示する。「全件取り込み」と解釈してはならない(誤 ingest 防止=書き込み副作用の安全側)。
    4. 除外指定された候補: pending_discoveries[] の当該エントリに declined: true を立て

Truncated - read the full file at https://github.com/aidotters/claude-code-wiki-maker/blob/b854ab2d11e7a8a8ce00dbf36c11cf5b0224da14/.claude/skills/llm-wiki/SKILL.md.

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/aidotters-claude-code-wiki-maker-llm-wiki/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

aidotters-claude-code-wiki-maker-llm-wiki.ocm.jsonjson
{
  "ocm": "1",
  "id": "aidotters-claude-code-wiki-maker-llm-wiki",
  "kind": "skill",
  "name": "llm-wiki",
  "description": "Claude Code 知識を raw→wiki にコンパイル蓄積。init/ingest/query/synthesize でボールト初期化・ソース取り込み・引用付き回答・派生成果物生成",
  "publisher": "aidotters",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "coding",
      "data_analysis"
    ],
    "tags": [
      "skill-md",
      "github"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "Claude Code 知識を raw→wiki にコンパイル蓄積。init/ingest/query/synthesize でボールト初期化・ソース取り込み・引用付き回答・派生成果物生成"
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "github",
      "repository": "https://github.com/aidotters/claude-code-wiki-maker",
      "path": ".claude/skills/llm-wiki/SKILL.md",
      "ref": "b854ab2d11e7a8a8ce00dbf36c11cf5b0224da14",
      "url": "https://github.com/aidotters/claude-code-wiki-maker/blob/b854ab2d11e7a8a8ce00dbf36c11cf5b0224da14/.claude/skills/llm-wiki/SKILL.md",
      "key": "aidotters/claude-code-wiki-maker/.claude/skills/llm-wiki/SKILL.md"
    },
    "allowed_tools": [
      "Read,",
      "Write,",
      "Edit,",
      "Glob,",
      "Grep,",
      "Bash,",
      "WebFetch,",
      "WebSearch,",
      "AskUserQuestion"
    ]
  },
  "instructions": "# llm-wiki(個人 Claude Code 知識ハブ)\n\n**目的:** 進化の速い Claude Code の知見を「検索ではなくコンパイル」して永続知識ベースに蓄積し、\n引用付きの派生成果物(チートシート/Tips 集)を生成・維持する。\n\n**引数:** `$ARGUMENTS`\n\n**使用方法:**\n```\n/llm-wiki init                                          # ボールト初期化・wiki-vault リンク案内・設定整備\n/llm-wiki ingest <path-or-url>                              # ソースを取り込みコンパイル(既存)\n/llm-wiki ingest <path-or-url> --type=practice              # practice ページとして取り込み(raw/notes/ 想定)\n/llm-wiki ingest <path-or-url> --feature=<slug>             # source 生成 + 指定 feature ページ更新\n/llm-wiki ingest <url> --watch                              # Tier B URL を watchl",
  "cost": {
    "context_tokens": 26075
  }
}

Fetch it by URL: GET /api/v1/registry/aidotters-claude-code-wiki-maker-llm-wiki/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.