Legwork
これは何のためか
意思決定リサーチ。学術調査ではない。問いは常に「Xについてどうすべきか」という類のものであり、成果物はそれが使いものになるかどうかで評価され、網羅的かどうかでは評価されない。
それが以下のすべてを形作っている。ある主張は、その主張に対してその情報源が正しい種類のものかどうかで判断され、情報源の分野が立派かどうかでは判断されない。三つの情報源が一致していても、それらが異議を唱えることができた場合にのみ意味を持つ。そして、問いに答えられない実行は、条件付きの長文を生成するのではなく、その旨を伝える。
自律性の原則。 必要なことはコンテキストから推測し、レベルを選び、開始せよ。レベルを一行で宣言して進め、ユーザーに選択を求めない。ユーザーは実行中に方向転換できる。これは、すべての要求に対してブロッキングクエスチョンを投げるよりもはるかにコストが低い。重大なエラーか意味不明なクエリの場合のみ停止する。
レベル
深さが厳密性を高める。長さは決して増えない。
| quick | standard | deep | |
|---|---|---|---|
| フレーミング | 意思決定と2〜3のサブ質問 | さらに明示的な反証仮説 | さらに二次的な視点 |
| 収集 | SERPのスニペット;数値を確定するためだけにフェッチ | 発見ごとにトップソースを直接フェッチ | 発見ごとに一次ソース |
| 検証 | 独立性グループ化のみ | 発見ごとに一つの反証検索 | 発見ごとの反証パスと発信元監査 |
| 形式 | brief | brief または report | report |
| ゲートレベル | --level quick | --level standard | --level deep |
| おおよその所要時間 | 3〜5分 | 8〜12分 | 20〜40分 |
デフォルトはstandard。ユーザーが指定したレベル(quick、standard、deep、または「クイックスキャン」「深掘り」などの同等表現)を使用し、それ以外の場合は$LEGWORK_DEFAULT_MODE、それもなければstandardを使用する。「ディープリサーチ」単体はこのスキルの呼び出しフレーズであり、deepレベルを要求するものではない — デフォルトにフォールスルーする。
スコーピングにより、質問がリクエストから想定されるよりも実質的に重要度が高いことが明らかになった場合、静かに1レベル上げ、同じ冒頭行でその旨を伝える。
冒頭行の後、すぐにフェーズ1へ:
standard(約8〜12分)で実行中。一次ソースと反証パスが必要な場合は「deep」と発言してください。
パイプライン
4つのフェーズ。完全な手順はmethodology.mdを参照。
- フレーミング - 意思決定、それを決着させるサブ質問、そして答えを変えるような証拠を特定する。
- 収集 - 各サブ質問に対して取得を実行し、すべてのフェッチを記録する。
- 検証 - 反証ケースを探索する;情報源を独立性でグループ化する。
- 執筆 - 成果物を組み立て、ゲートを通過させる。
フェーズ2と3は厳格なゲートとして実行するのではなく、発見ごとにインターリーブされる。
開始前に行うこと
日付を固定する。 date -u +%Y-%m-%d を実行し、その文字列を実行、出力フォルダ名、および日付が関係する可能性のあるすべての検索クエリに使用する。自分の年数感覚に決して頼らず、サブエージェントにそれを自動解決させてはならない。
この実行がすでに行われていないか確認する。 まずインデックスを読む。これはディスパッチャである:過去の実行ごとに1行あり、ワンライナー列はレポートを開くコストを払わずに開くべきか判断できるように存在する。
python3 ${CLAUDE_SKILL_DIR}/scripts/index.py list --base "$OUTPUT_BASE"
次に4つのパスのいずれかを選び、冒頭行でその旨を伝える:
| インデックスの内容 | 実行すること |
|---|---|
| これをカバーする実行があり、古くなっていない | それから回答する。そのレポートを読み、ウェブは読まない。 |
| これをカバーする実行があるが、古いとフラグが立っている | リフレッシュする |
| 近い実行があるが、別の質問に答えている | 新規実行し、相互参照する |
| 一致するものがない | 新規実行 |
過去の実行から回答することは成功であり、近道ではない。 レポートを開き、質問に関係する発見を読み、その信頼度帯をそのままにして回答する。それが特定の日付の実行に由来することを明確に述べる。すでに行われ、まだ有効なリサーチを再実行することは、このインデックスが防ごうとしている無駄である。
再実行ではなくリフレッシュ
リフレッシュは既存のレポートをその場で更新する — 同じフォルダ、同じファイル。2つ目のフォルダを作成してはならない:1つの質問を説明する2つのフォルダは、読者がたまたま開いた方に基づいて行動する原因となる。
-
新しいフェッチログを開始するのではなく、再開する。フェッチログ内のすべての情報はすでに支払い済みである。
python3 ${CLAUDE_SKILL_DIR}/scripts/sources.py resume --tsv "$OUT/$BASE.tsv"これにより、すでに処理された角度、すでにフェッチされたページ、およびまだ引用がないページが表示される。未カバーの角度を処理し、答えを決定する主張を再検証する;すでに記録され、最新のものを再フェッチしてはならない。
-
現在間違っているすべての主張を、日付と理由とともに
## Supersededに移動する。主張を黙って削除してはならない。 誰かがそれに基づいて行動した可能性があり、将来の実行はこの領域がすでにカバーされていることを知る必要がある。同じ答えが今までに2回覆された場合は、それを明確に伝える — それはドキュメントの中で質問が不安定であることを示す最も強いシグナルである。 -
変更内容を
## Timeline行に追加する。 -
インデックス行を更新する。
実行のファイリング
すべての実行はインデックスに格納される。答えられなかった実行も含む — 「調べたが何も見つからなかった」という情報こそ、将来のセッションが再度調べる必要をなくすために必要なものである。
python3 ${CLAUDE_SKILL_DIR}/scripts/index.py add --base "$OUTPUT_BASE" \
--folder "$BASE" --topic "小規模診療所のアウトルクトリアージ" --level deep \
--one-liner "E5未満ではネイティブトリアージなし;ギャップは実在するが狭い"
ワンライナーは実行が結論づけたことを述べ、何についてのものかを述べてはならない。6か月後には「プラグインギャラリーに関するメモ」は役に立たないが、「提出経路は存在せず、インストールはURLによるか全くできない」はそれ自体で質問に答えている。ゲートは、存在するインデックスから実行が欠落している場合に警告する。
取得ポリシー
2つのラダー。無料の段を最初に。必要なところまでだけ登る。
検索用:
| 段 | 呼び出し | タイミング |
|---|---|---|
| 1 | WebSearch | 常に。角度ごとに3つのクエリバリエーション。 |
| 2 | platforms.py search --on ... | 答えがプラットフォームが保持するレコードである場合:スレッド、パッケージ、リポジトリ、日付付きニュースアイテム、ベンダーの変更履歴。無料、キー不要で、それについてのページではなくレコードを返す。 |
| 3 | bd_search.py -m general --engine bing --country XX --language yy | 3つのバリエーションで結果が薄い場合、または質問が地域固有の場合。2つ目のエンジンを使うために対価を払う理由。 |
| 4 | bd_search.py -m discover --intent "..." | 2つのエンジンでもまだ薄い場合。 |
ページを開く用:
| 段 | 呼び出し | タイミング |
|---|---|---|
| 1 | fetch.py "<url>" --find "term" | 常に最初。無料で、ページテキストを生成する唯一の無料トランスポートであるため、数値の追跡と引用の確認が可能。 |
| 2 | WebFetch | fetch.py が終了コード3で終了し、そのページに対価を払う価値がない場合。 |
| 3 | bd_search.py "<url>" -m scrape | ブロックされた場合:ボット対策、ペイウォール、403エラー。 |
| 4 | bd_search.py "<url>" -m render | クライアントサイドレンダリングのシェルの場合。 |
| 5 | bd_search.py "<url>" -m pipeline --pipeline NAME | 上記すべてをブロックするプラットフォームの場合。レコード単位で課金;-m redditは、それが唯一の経路であり、最後の手段ではない場合のみ使用。 |
platforms.py list で10の無料プラットフォームを確認し、bd_search.py --help で有料モードを確認する。終了コード2(認証またはクォータ)の場合、ユーザーに brightdata login を実行するよう伝える。再試行してはならない。
検索結果はリードであり、読むページではない。 standard および deep では、引用するものを開く:ゲートは websearch 行のみに依存する引用を未開封として扱い、standard では警告、deep ではエラーとなる。Quick はスニペット優先が設計上の特徴であり、求められない。
フォールバックの前に失敗を記録する。 開かなかったページは実行に関する証拠であり、--status blocked として記録し、領収書はそれをカウントする。
プルバックする量に上限を設定する。 スクレイプ呼び出しには --max-chars 8000 を使用し、盲目的な上限よりは --find を優先する:長いページでは、最初の8000文字は通常ナビゲーションである。
使用してよい情報源
リサーチとは、部外者が確立できるものである。この境界は両方向で重要である。
ユーザー自身の記録を発見として提示してはならない。 質問がユーザー自身の会社、製品、または市場ポジションに関するものである場合、ユーザーのプライベートアカウント(レジストラ、請求書、受信箱、内部ファイル)にアクセスし、そこで見つけたものを発見されたかのように報告してはならない。ユーザーはすでにそれを知っている。それは循環論法であり、見かけ上の証拠を膨らませ、部外者が実際にどれだけ見ることができるかを隠蔽する。公開されている同等のものを検索し、部外者が見つけるものを報告する。何も見つからなくても、それを報告する。
ユーザーから与えられた排他的アクセスを、第三者に対しては使用してよい。 ユーザーが明示的に提供した有料サブスクリプション、プライベートデータセット、または内部データベースは、競合他社、サプライヤー、または市場を調査する際の真のアドバンテージである。それを使用し、他の情報源と同じように記録し、制限事項にその発見が読者が持っていないかもしれないアクセスに依存していることを明記する。
あるエンティティに公開フットプリントがまったくないことが判明した場合、それが答えである。確認したものをリストし、存在や規模が外部から検証できなかったことを述べ、特権アクセスからギャップを埋めてはならない。これは「答えられなかった」という形状を、質問全体ではなく1つのエンティティに適用したものである。
フェッチログ
すべての取得は、すべてのレベルで、1行を追加する:
python3 ${CLAUDE_SKILL_DIR}/scripts/sources.py log \
--tsv "$OUT/$BASE.tsv" \
--url "https://acme.example/pricing" \
--kind vendor_pricing \
--angle "競合他社はいくら請求するか" \
--via webfetch \
--date 2026-07-01 \
--title "料金" \
--quote "チームプラン:月額ユーザーあたり30米ドル、年払い。" \
--text-file /tmp/page.txt
2つのフィールドが重みを持ち、どちらも後続の処理ではチェックできない。
--angle は、この取得が答えていたサブ質問である。裏付けは情報源ではなく角度でカウントされる。なぜなら、Legwork 自身の展開が情報源の数を水増しするからである。角度を正直に記録せよ — 実行全体で同じ文字列を再利用すると、チェックが黙って破壊され、どのスクリプトもそれを検出できない。
--quote は、その情報源を引用する価値があると判断した根拠となった、そのままの文である。引用するつもりのすべての情報源について、読んだ時点で1つ記録せよ。 すべての発見の約半数は数値を含まないため、その場合、引用が唯一の証拠であり、ページが変更された後も生き残る唯一の部分である。ページテキストがディスク上にある場合(fetch.py で開いたもの、または --out 付きの -m scrape)、引用はそれに対してチェックされ、quote_verified: false はページを誤って引用したことを意味する。
--from-fetch は、URL、タイトル、日付、ページテキストを、これら2つが書き込むサイドカーから入力するため、再入力の必要がない:
python3 ${CLAUDE_SKILL_DIR}/scripts/sources.py log --tsv "$OUT/$BASE.tsv" \
--from-fetch /tmp/legwork/ab12cd34ef56.json \
--angle "競合他社はいくら請求するか" --kind vendor_pricing \
--query "site:acme.example 料金" --quote "チームプラン:月額ユーザーあたり30米ドル..."
sources.py log --help で残りのオプションを確認:--via トランスポート(api、local、mcpを含む)、--text-file 数値抽出、--kind。実際に使用したトランスポートを記録せよ — ログ可能にするために別のトランスポートでページを再フェッチすることは、証跡を歪めるのであって記録することではない。sources.py kinds は、どの情報源の種類がどの主張に適しているかを表示する。
サブエージェント
取得は並列化する価値がある唯一のフェーズであり、角度ごとに1つのサブエージェントを使用する。サブエージェントへの指示は subagent-brief.md から与える。このファイルには、テンプレートの正確な文言、必要な戻り値の形状、および各行がそこにある理由が記載されている。サブエージェントはコンテキストがゼロであるため、必要なものはすべて指示に含める。
3つの事項は、指示ではなく、あなたの側に残る:
- 角度の形状にモデルを合わせる。 スニペット収集や既知の数値の固定は、安価なモデルで十分に動作する — オーバーライドを明示的に渡し、決してセッションモデルを誤って継承させてはならない。しかし、deep レベルの一次ソース作業、および列挙を再構築するものは、オーケストレータのモデルに留める。 測定値:ある比較では、オーケストレータは安価から高性能の範囲で3、8、32のベンダーページを開き、最も弱いモデルだけが単一のアグリゲータからグリッドのすべてのセルを埋めて成功を報告した。
- サブエージェントのトランスクリプトを合成に貼り付けてはならない。 構造化された戻り値を受け取り、角度文字列が変更されずに返ってきたことを確認し、各行をログに記録し、ログから作業する。
- スコーピング、検証、合成は判断を要する。 これらはメインモデルに留める。
スクリプト
すべて標準ライブラリのみ。仮想環境は不要。任意の python3 >= 3.9。
| スクリプト | 目的 |
|---|---|
fetch.py "<url>" --find TERM | ページを無料で開き、そのテキストを保持する;ブロックまたはシェルの場合、終了コード3で終了 |
platforms.py list | search --on X | 10の無料プラットフォームネイティブソース。ページではなくレコードを返す |
sources.py kinds | log | score | 情報源の種類の語彙、フェッチログ、主張の種類ごとの適合性スコアリング |
sources.py receipt | 領収書行のための取得カウント、ログから取得 |
sources.py stale --claim-kind K | その主張の種類の半減期に基づいて、ログに記録されたどの情報源が古くなったか |
sources.py resume | 以前の実行がすでにフェッチしたもの。再実行でスキップするため |
independence.py groups | check | 情報源を独立した声にまとめる;角度を認識した裏付けをカウントする |
independence.py portfolio | 1つの発見内ではなく、実行全体にわたる情報源の集中度 |
index.py add | list | リサーチインデックス — 実行をファイルする、過去のものを見つける、古いものを特定する |
matrix.py check --report PATH | 比較マトリックスの完全性 |
check.py --report PATH --level LEVEL | 出荷可能かどうかのゲート |
finish.py --report PATH --level LEVEL | ゲート、陳腐化スイープ、ファイリングを1回の呼び出しで |
bd_search.py "<query|url>" -m MODE --json | Bright Data 取得フォールバック |
出力
実行の開始時に一度出力ベースを解決する:
OUTPUT_BASE="${LEGWORK_OUTPUT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)/docs/research}"
BASE="[Topic]_Research_$(date +%Y%m%d)"
OUT="$OUTPUT_BASE/$BASE"; mkdir -p "$OUT"
…
[翻訳のため省略]