Book-to-Skillコンバーター
書かれた知識を、要約ではなく構造を抽出することで、実行可能なエージェントスキルに変換します。
哲学
書籍には結晶化された専門知識(フレームワーク、原則、テクニック)が含まれており、それらは開発に何年もかかったものです。このスキルは、その知識をGitHub Copilot CLI、Amp、Claude Code、Hermes Agent、またはその他の互換性のあるエージェントが繰り返し利用できる形式に抽出します。
構造を抽出し、要約は作成しません。 スキルは読書感想文ではありません。それは以下のツールキットです:
- 名前付きフレームワーク(明確な適用方法があるメンタルモデル)
- 実用的な原則(意思決定を導くルール)
- テクニック(ステップバイステップの方法)
- アンチパターン(避けるべきこととその理由)
- ボイスキャリブレーション(著者の思考と伝達方法)
著者の正確さを保持します。 フレームワークには、しばしば特定の名前が理由があって付けられています。「5つのなぜ」は「なぜを何度も尋ねる」と言い換え可能ではありません。正確な定式化を捉えます。
深さを適切に階層化します。 シンプルな本 → シンプルなスキル。10以上のフレームワークを持つ複雑な本 → 参照ファイルとオンデマンドチャプターを持つスキル。
動作モード
4つのパスが利用可能です。ユーザーのリクエストに基づいてルーティングします:
1. 完全変換(デフォルト)
トリガー: ユーザーが特別な指示なしに1つ以上のドキュメント/ディレクトリ/グロブパスを提供 アクション: 以下の全ステップ(ステップ0~9)を実行 出力: SKILL.md、chapters/、用語集、パターン集、チートシートを含む完全なスキル
2. 分析のみ
トリガー: ユーザーが「分析」、「抽出だけして」、「生成前にレビューしたい」と言った場合 アクション: ステップ0~3を実行し、構造化抽出レポート(見つかったフレームワーク、原則、テクニック)を生成。停止 — スキルファイルは生成しません。 出力: ユーザーレビュー用の分析レポート
3. 事前分析から生成
トリガー: ユーザーが既存の分析ノートを持っているか、以前に分析のみを実行した場合 アクション: ステップ0~3をスキップし、提供された分析を入力として使用し、ステップ4~9を実行 出力: 提供された分析からのスキルファイル
4. 更新/統合(既存スキル)
トリガー: ユーザーが1つ以上の新しいソースパスを提供し、既存のスキルを更新したいことを示した場合(既存のスキルフォルダを指定する、SKILLS_HOMEにすでに存在するスキルスラッグを指定する、または明示的に更新を要求する)。
アクション: ステップ0(範囲外チェック)、ステップ1(入力検証)、ステップ1.5(コンテンツタイプ識別)、ステップ2(新しいファイル抽出)を実行。次にステップ5(既存スキルパスの識別/検出)にスキップし、更新/統合ワークフローを実行して新しいコンテンツを既存のスキルファイルにマージします。
出力: 新しい/改訂されたチャプター要約とマージされたインデックス/用語集で更新された既存のスキル。
スキル配置場所
このコンバーターは複数のスキルシステムから実行できます。このコンバーターのヘルパースクリプトを探したり、生成されたブックスキルを書き込むときは、以下の場所をこの順序で優先します:
- GitHub Copilot CLI個人スキル:
~/.copilot/skills/ - クロスエージェント個人スキル(Copilot、Amp、Codex):
~/.agents/skills/ - Claude Code個人スキル:
~/.claude/skills/ - プロジェクトローカルCopilotスキル:
.github/skills/ - プロジェクトローカルClaudeスキル:
.claude/skills/ - プロジェクトローカルAmp / Copilotスキル:
.agents/skills/ - Ampグローバルスキル:
~/.config/agents/skills/ - Ampレガシーグローバルスキル:
~/.config/amp/skills/ - Hermes Agent個人スキル:
$HERMES_HOME/skills/(デフォルトは~/.hermes/skills/) - Hermes Agentプロジェクトスキル:
.hermes/skills/または.agents/skills/
生成されたブックスキルについては、ユーザーレベルのクロスエージェントルート ~/.agents/skills/ を優先します — 1つの物理コピーでサポートされているすべてのホストにサービスを提供します。Copilot CLIとAmpはネイティブにそれを発見します。Claude Codeは~/.claude/skills/<skill_name>からのシンボリックリンクが必要です(ステップ10で作成。ルールはステップ5を参照)。ユーザーが明示的に要求した場合にのみ、ホストプライベートまたはプロジェクトローカルルートを選択します。
ステップ0 — 範囲外チェック
引数が提供されていない場合、停止して応答します:
「book-to-skill はサポートされているドキュメントパス、フォルダ、またはグロブパターンを必要とします。使用法:
book-to-skill <path-to-document-folder-or-glob>... [skill-name-slug]」
ワークフロー全体を通して:
- 入力パスとオプションのスキルスラッグを特定します。
- 最後の引数がファイル、フォルダ、または存在するグロブではなく、スキルスラッグのように見える場合(例: 小文字のハイフン、英数字)、それを
SKILL_NAMEとして扱います。 - 他のすべての引数を
INPUT_PATHSのリストとして扱います。 - いずれかの入力パスが既存のスキルディレクトリ(
SKILL.mdとchapters/サブフォルダを含む)である場合、またはSKILL_NAMEがSKILLS_HOME内の既存のスキルスラッグと一致する場合、この実行を更新/統合操作(モード4)としてフラグ付けします。
ステップ1 — 入力の検証
INPUT_PATHSの中に少なくとも1つのサポートされているファイル、ディレクトリ、またはグロブパターンがあることを確認します。
ディレクトリとグロブについては、それらを展開してサポートされているファイル(.pdf、.epub、.docx、.txt、.md、.markdown、.rst、.adoc、.html、.htm、.rtf、.mobi、.azw、.azw3)を見つけます。
サポートされているファイルが見つからない場合、明確なエラーメッセージを表示して停止します。
ステップ1.5 — コンテンツタイプの識別
抽出前に、ユーザーに尋ねます:
「これらのソースにはどのような種類のコンテンツがありますか?これは最適な抽出方法を選ぶのに役立ちます。
- 技術系 — コードブロック、テーブル、数式、図が含まれる(例: プログラミング書籍、学術論文、アーキテクチャガイド)
- テキスト主体 — 大部分が散文、テーブル/コードはほとんどない(例: マネジメント、生産性、ノンフィクション)
- わからない — 高速な方法を使用し、品質が制限される場合は警告します」
答えをBOOK_TYPEとして保存します:
- オプション1 →
BOOK_TYPE=technical - オプション2 →
BOOK_TYPE=text - オプション3 →
BOOK_TYPE=text
もしBOOK_TYPE=technicalの場合、続行する前にユーザーに知らせます:
「📐 テクニカルモードが選択されました — 構造認識抽出(テーブル、コードブロック、数式はマークダウンとして保持)にDoclingを使用します。1ページあたり約1.5秒かかるため、長いソースでは数分かかることがあります。開始します…」
もしBOOK_TYPE=textの場合、次のように知らせます:
「📄 テキストモードが選択されました — 各ファイルタイプに最も適した最速の抽出器を使用します。プレーンテキスト/マークダウン/HTMLは通常数秒で準備完了。PDFはpdftotextが利用可能な場合に使用します。」
ステップ2 — ソースドキュメントからテキストを抽出
抽出スクリプトを実行し、入力パスを渡します:
SCRIPT_PATH=""
HERMES_HOME_RESOLVED="${HERMES_HOME:-$HOME/.hermes}"
PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"
HERMES_PROJECT_TRUSTED=false
if [ -n "$PROJECT_ROOT" ] && [ "${HERMES_AGENT:-}" = true ] && \
command -v hermes >/dev/null 2>&1 && \
command -v python3 >/dev/null 2>&1 && \
hermes config get skills.trusted_project_dirs --json 2>/dev/null | PROJECT_ROOT="$PROJECT_ROOT" python3 -c 'import json, os, pathlib, sys; root=pathlib.Path(os.environ["PROJECT_ROOT"]).resolve(); sys.exit(not any(pathlib.Path(p).expanduser().resolve() == root for p in json.load(sys.stdin)))' 2>/dev/null
then
HERMES_PROJECT_TRUSTED=true
fi
CANDIDATES=(
"$HOME/.copilot/skills/book-to-skill/scripts/extract.py"
"$HOME/.agents/skills/book-to-skill/scripts/extract.py"
"$HOME/.claude/skills/book-to-skill/scripts/extract.py"
"$HERMES_HOME_RESOLVED/skills/book-to-skill/scripts/extract.py"
"$HERMES_HOME_RESOLVED"/skills/*/book-to-skill/scripts/extract.py
)
if [ "${HERMES_AGENT:-}" != true ]; then
CANDIDATES+=(
".github/skills/book-to-skill/scripts/extract.py"
".claude/skills/book-to-skill/scripts/extract.py"
".agents/skills/book-to-skill/scripts/extract.py"
)
fi
CANDIDATES+=(
"$HOME/.config/agents/skills/book-to-skill/scripts/extract.py"
"$HOME/.config/amp/skills/book-to-skill/scripts/extract.py"
)
if [ "$HERMES_PROJECT_TRUSTED" = true ]; then
CANDIDATES=(
"$PROJECT_ROOT/.hermes/skills/book-to-skill/scripts/extract.py"
"$PROJECT_ROOT/.hermes/skills"/*/book-to-skill/scripts/extract.py
"$PROJECT_ROOT/.agents/skills/book-to-skill/scripts/extract.py"
"$PROJECT_ROOT/.agents/skills"/*/book-to-skill/scripts/extract.py
"${CANDIDATES[@]}"
)
fi
for candidate in "${CANDIDATES[@]}"
do
if [ -f "$candidate" ]; then
SCRIPT_PATH="$candidate"
break
fi
done
if [ -z "$SCRIPT_PATH" ]; then
echo "book-to-skillのscripts/extract.pyが見つかりません" >&2
exit 1
fi
PYTHON_BIN="${PYTHON_BIN:-python3}"
if ! command -v "$PYTHON_BIN" >/dev/null 2>&1; then
PYTHON_BIN="python"
fi
"$PYTHON_BIN" "$SCRIPT_PATH" $INPUT_PATHS --mode <BOOK_TYPE> --install-missing ask
抽出前に、スクリプトは検出された形式に必要なオプションのPythonパッケージをチェックします。より良い抽出器がない場合、利用可能なフォールバックをユーザーに促します。非対話型セッションでは、インストールモードが明示的にyesでない限り、デフォルトでフォールバックを使用します。
ヒント — 環境の事前確認: "$PYTHON_BIN" "$SCRIPT_PATH" --checkを実行すると、インストールされている抽出器の形式ごとのレポートと、不足しているものをインストールするための正確なコマンドが、ファイルを処理せずに表示されます。ユーザーがセットアップや品質の問題を報告した場合に便利です。
これにより、実行ごとの作業ディレクトリが作成されます — デフォルトでは<tempdir>/book_skill_work-<pid>/、またはBOOK_SKILL_WORKDIRで設定したパス — 以下を含みます:
full_text.txt— すべてのソースの結合抽出テキスト。明確に視覚的に区切られた境界が付いています。metadata.json— 全体の結合サイズ、単語数、ページ数、トークン数、削除されたEPUB画像数、解決されたworkdir、および個別に処理されたsourcesの詳細なリスト。
実行は完了時にこれら3つのパスすべてを出力します(Workdir ->、Text ->、Meta ->)。固定された場所を想定するのではなく、その出力(またはmetadata.jsonのworkdirフィールド)からパスを取得してください — ディレクトリ名は実行ごとに異なり、1台のマシンでの同時抽出が互いの結果を上書きするのを防ぎます。
その実行のmetadata.jsonを読み取って結果を検査します。
何かを生成する前に、常に抽出が要求されたドキュメントであることを確認してください: metadata.jsonのfilename / source_file、またはfull_text.txtの最初の行のSOURCE:ヘッダーを確認します。バックグラウンド実行を待機している場合は、その特定の作業ディレクトリを待機してください — 共有パスをポーリングすると、別の実行の出力が表示される可能性があります。
ステップ2.5 — 事前コスト見積もり
この実行のmetadata.json(抽出出力からのMeta ->パス)を読み取り、生成を行う前に見積もりをユーザーに提示します:
📖 検出されたソース: <total_sources> ソース
<ソースメタデータリストから各ソースのファイル名と形式をリスト>
<もしimages_dropped > 5: N個のソース画像が読み取られなかったことを警告>
📄 結合ページ/セクション: ~<N> | 単語数: ~<N> | 合計トークン: ~<N>K
💰 推定トークンコスト(完全変換/更新):
入力(読み取り + プロンプト): ~<N>K トークン
出力(生成/更新されるスキルファイル): ~<N>K トークン
合計: ~<N>K トークン
コスト: 上記のトークン数に、使用中のモデルの現在の
入力/出力 100万トークンあたりのレートを掛けてください(価格とモデル名は
頻繁に変わります — ハードコードせず、今日のレートを引用し、推定とラベル付けしてください)。
⏱ 推定時間: ~<N> 分
📁 生成/更新されるファイル:
SKILL.md + チャプターファイル + 用語集 + パターン集 + チートシート
➡ 完全変換/更新を続行しますか?(または、先にプレビューするには「analyze only」と入力)
見積もり方法:
- 入力トークン ≈ メタデータからの
estimated_tokens× 1.3(チャプターごとのプロンプトオーバーヘッド) - 出力トークン ≈ チャプター数 × チャプターごとの予算 + 4,000(SKILL.md) + 4,500(用語集 + パターン集 + チートシート)
BOOK_TYPEによるチャプターごとの予算の中間値(深さはステップ4で後で決定され、引き上げ可能):text≈ 1,000、technical≈ 1,800。ユーザーがすでに参照のみか深い学習かを示している場合は、ステップ7のマトリックスの該当する行を使用します。
- コスト: トークン数を報告し、ユーザーの現在の入力/出力 100万トークンあたりのレートを掛けます。ドル金額はハードコードしないでください — モデル名と価格は変わります。表示する場合は、推定値とラベル付けし、日付を記入してください。
続行する前にユーザーの確認を待ちます。ユーザーが「analyze only」と言った場合は、モード2に切り替えます。
ステップ2.6 — 大規模ブック用のREPLスタイルアクセス(50kトークン超)
再帰的言語モデル(RLM)パラダイムに触発されました: full_text.txtを単一の読み取りとしてではなく、クエリ可能なコーパスとして扱います。ファイル全体をコンテキストにロードすると、後で生成に必要な予算を消費します。
約50kトークンを超える書籍の場合は、制限なしのRead(full_text.txt)よりもプログラムによるプローブを優先します:
# 読み取り前のサイズチェック
wc -w "$FULL_TEXT_PATH"
# ファイル全体をロードせずにチャプターのオフセットを見つける
grep -n -E "^\s*(Chapter|CHAPTER)\s+[0-9]+" "$FULL_TEXT_PATH" | head -40
# 必要なチャプターのみをプル(開始行..終了行を含む)
sed -n '<start>,<end>p' "$FULL_TEXT_PATH"
# SKILL.mdで主張する前に、フレームワークが実際に言及されていることを確認
grep -c -i "westrum\|dora" "$FULL_TEXT_PATH"
# オフセット/制限を指定したターゲット読み取りにより、全ファイルのダンプを回避
# Read(file_path=full_text.txt, offset=<line>, limit=<lines>)
このアプローチをステップ3(構造分析)、ステップ7(チャプターごとの要約)、ステップ8(用語集/パターン抽出)で使用します。50kトークン未満の書籍では、単一のReadで問題ありません。
これが重要な理由: 200ページの本は約75kトークンです。チャプターごとに1回読み直すと(28パス)、多くのトークンを消費します。