mcpField
D
devtu-docs-quality

devtu-docs-quality

github.com/mims-harvardテスト・品質1.8k181 回インストール2 日前に更新
リポジトリ

devtu-docs-quality について

ToolUniverse の保守担当者向けに、技術的な正確さと文書の簡素化を点検する QA スキルです。段階的な静的チェック、スキル内のツール呼び出し検証、監査チェックリストを備えています。

主な機能

  1. 01技術的正確性を優先
  2. 02重複や古い内容を削除
  3. 03無効なメソッド呼び出しを検出
  4. 04スキル内のツール呼び出しを検証
  5. 05リンク、分量、ナビゲーションを確認

活用シーン

  1. 01ToolUniverse の文書変更をレビュー
  2. 02スキル例の無効なツール呼び出しを発見
  3. 03重複または古いセットアップ説明を整理
  4. 04リリース前に文書を点検

MCP 対応

入力には、このスキルと MCP の関係は記載されていません。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mims-harvard/tooluniverse --skill devtu-docs-quality

インストール後、Claude Code で/devtu-docs-qualityを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

API_REFERENCE.md
DOCS_STRUCTURE.md
EXAMPLES.md
SUMMARY.md

詳細

ドキュメントの品質保証

2 つの同等に重要な優先事項

監査を行う前に、以下の両方を満たす必要があります。どちらか一方がもう一方に優先することはありません。

1. 技術的な正確さ — 誤ったコードは、コードがないことよりも悪く、ユーザーのワークフローを実際に壊します。

2. 少ないほどよい — 冗長なコンテンツは、コンテンツがないことよりも悪く、混乱を招き、信頼を損ない、メンテナンスを難しくします。

技術的な正確さに疑問がある場合:ソースを確認してください(src/tooluniverse/execute_function.py)。 コンテンツが必要かどうかに疑問がある場合:削除してください。


少ないほどよい — 基本理念

ToolUniverse は本格的な研究ツールです。ドキュメントにも、量ではなく抑制と正確さを反映させる必要があります。

実践における「少ないほどよい」の意味

追加するのではなく、削除します。 編集のたびに、語数、ページ数、リンク数を減らしてください。分野の変化は速く、古い手順はユーザーに実害を及ぼします。どちらの方法も有効なら、片方だけ残してください。

各コンセプトは一度だけ記載します。 セットアップ手順が 3 か所に記載されていると、いずれか 1 か所を読んだユーザーはほかにも記載があることに気づけず、メンテナーは変更のたびに 3 か所すべてを更新しなければなりません。正式な記載場所を 1 か所に決め、ほかの場所からはすべて相互リンクしてください。

絵文字は使いません。 見出し、ナビゲーション項目、カードタイトル、箇条書きの絵文字は「AI 生成」を連想させ、本格的な科学ツールへの信頼を損ないます。強調目的の例外もなく、必ず削除してください。

要約するのではなく、短くします。 1000 行のページを TL;DR ボックスで要約するより、1000 行のページを 30 行の案内に短縮するほうが望ましいです。思い切って整理してください。

サイズの上限(厳守):

ページの種類最大行数
プラットフォーム別セットアップページ(claude_desktop.rst、cursor.rst など)15
ホームページのグリッドセクショングリッドごとに最大 4 枚のカード
「関連項目」/「関連情報」のリンクリスト最大 4 件のリンク
Python ガイドと重複するチュートリアルページ0 — 削除するか、案内のみにする
「少ないほどよい」の判断フロー

コンテンツを見直す際は、次の点を確認してください。

  1. このコンテンツはサイト内の別の場所にもありますか? → 削除し、正式な記載場所への相互リンクを追加します。
  2. このコンテンツは古くなっている、または最新状態の維持が難しいですか? → 削除し、上流の情報源(例:aiscientist.tools/setup.md)にリンクします。
  3. ユーザーはホームページから 2 回のクリックでこの情報にたどり着けますか? → たどり着けて情報がすでに掲載されている場合、このコピーを削除します。
  4. これは絵文字、装飾的な見出し、または埋め草の文章ですか? → 必ず削除します。
  5. サイドバーですでにアクセスできる場所への「詳細を見る」カードですか? → 削除します。

Apple スタイルの簡素化ルール

監査中に編集するすべてのファイルに、これらのルールを適用してください。

見出し、箇条書き、カードタイトル、toctree のキャプション、ナビゲーションバーの項目、ボタンのテキストに絵文字を使わないでください。

セットアップの入口は 1 か所にします。 正式なインストール手順は次のとおりです。

Read https://aiscientist.tools/setup.md and set up ToolUniverse for me.

プラットフォーム別のページに記載するのは、次の 3 点だけです。(1)公式インストールリンク、(2)公式 MCP セットアップガイドへのリンク、(3)上記のセットアッププロンプト。ほかには何も記載しません。JSON スニペット、手順ごとの説明、トラブルシューティングは記載しないでください。それらは aiscientist.tools/setup.md のセットアップスキルに記載します。

ツール数の表記を統一します。 常に「1000+ ツール」と表記します。「600+」、「750+」、「1200+」、「10000+」など、ほかの数は使いません。

ナビゲーションバーを整理します。 「API」、「API Keys」、「Contribution」の項目を含めてはいけません。最初の項目には https://aiscientist.tools へのリンクを含めてください。

ホームページの「詳細を見る」グリッド。 カードは最大 4 枚です。リンク先にサイドバーまたは「はじめに」セクションからすでにアクセスできるカードは削除してください。

壊れた :doc: 参照を残さないでください。 すべての :doc:some/path`` は、ディスク上の .rst または .md ファイルに解決される必要があります。壊れたリンクは決して許容されません。すぐに削除するか、置き換えてください。


5 フェーズの戦略

フェーズは順番に実行します。まず D(即時)、次に E(簡略化スキャン)、その後に C/A/B を実行します。

フェーズ検出する内容所要時間
D 静的メソッドスキャンメソッド名の誤り(tu.run_batch、tu.call_tool など)約 2 秒
E 簡略化スキャン絵文字、件数の誤り、リンク切れ、サイズ違反約 10 秒
C ライブコード実行実行時エラー(キーの誤り、戻り値の型の誤り)3~5 分
A 自動検証非推奨コマンド、用語の不統一15 分
B ToolUniverse の監査ナビゲーションの循環、MCP 設定の重複、ツール数20 分

フェーズ D:静的メソッドスキャン

python3 - <<'EOF'
import re, sys
from pathlib import Path
from collections import defaultdict
DOCS = Path("docs")
EXCLUDE = {"locale", "old", "_build", "__pycache__", "tools", "archive"}
KNOWN_BAD = {
    "list_tools", "run_batch", "run_async", "execute_tool", "call_tool",
    "list_tools_by_category", "configure_api_keys", "get_tool", "get_exposed_name",
    "list_available_methods", "register_tool_from_config", "register_tool",
}
STATIC = [
    (r"\.load_tools\([^)]*(?:use_cache|cache_dir)\s*=", "load_tools() invalid kwargs"),
    (r"ToolUniverse\([^)]*timeout\s*=", "ToolUniverse(timeout=) invalid"),
    (r'"name":\s*"opentarget_', 'old lowercase "opentarget_*" tool name'),
    (r"tu\.run_batch\(", "tu.run_batch() — use tu.run(list, max_workers=N)"),
    (r'\btu\.[A-Z]\w+\s*\(', "tu.ToolName() shorthand — use tu.run({name:...})"),
]
M = re.compile(r'\b(?:tu|tooluni)\.([\w]+)\s*\(')
issues = defaultdict(list)
for f in sorted(list(DOCS.rglob("*.rst")) + list(DOCS.rglob("*.md"))):
    if any(p in f.parts for p in EXCLUDE): continue
    t = f.read_text(errors="replace")
    code = "\n".join(
        re.findall(r"\.\. code-block:: python\n((?:[ \t]+[^\n]*\n|[ \t]*\n)*)", t, re.MULTILINE) +
        re.findall(r"```python\n(.*?)```", t, re.DOTALL))
    if not code.strip(): continue
    rel = str(f.relative_to(DOCS))
    for m in M.finditer(code):
        if not m.group(1).startswith("_") and m.group(1) in KNOWN_BAD:
            issues[rel].append(f"tu.{m.group(1)}()")
    for pat, label in STATIC:
        if re.search(pat, code): issues[rel].append(label)
if issues:
    [print(f"  {f}: {i}") for f in sorted(issues) for i in sorted(set(issues[f]))]
    sys.exit(1)
else:
    print("Phase D clean")
EOF

修正または削除のルール — 例外なし:

  • 正しい置き換え方法がある → すぐに修正
  • 機能が自動または内部処理である → 呼び出しを削除し、必要に応じて説明コメントを追加
  • 機能が存在しない → コードブロックまたはセクション全体を削除

よくある修正:

# wrong → correct
tu.run_batch(list)              → tu.run(list, max_workers=4)
tu.run_async(query)             → await tu.run(query)
tu.call_tool('X', {...})        → tu.run({"name": "X", "arguments": {...}})
tu.execute_tool('X', {...})     → tu.run({"name": "X", "arguments": {...}})
tu.list_tools()                 → tu.list_built_in_tools(mode='list_name')
tu.get_tool('X')                → tu.get_tool_by_name('X')
tu.register_tool(instance)      → tu.register_custom_tool(tool_instance=instance)
tu.register_tool_from_config(c) → tu.register_custom_tool(tool_config=c)
tu.configure_api_keys({})       → REMOVE — use env vars
tu.get_exposed_name(name)       → REMOVE — shortening is automatic
ToolUniverse(timeout=30)        → ToolUniverse()  # no timeout kwarg
load_tools(use_cache=True)      → load_tools()  # no use_cache kwarg
tu.ToolName(key=val)            → tu.run({"name": "ToolName", "arguments": {"key": val}})
opentarget_get_*                → OpenTargets_get_*  (capital O and T)

特別なケース: 意図的に誤ったコードをエラー例として示す場合は、.. code-block:: python を .. code-block:: text に変更します。


フェーズ E:簡略化スキャン

python3 - <<'EOF'
import re, sys
from pathlib import Path

DOCS = Path("docs")
EXCLUDE = {"_build", "__pycache__", "locale"}
issues = []

EMOJI_RE = re.compile(
    r'[\U0001F300-\U0001F9FF\U00002600-\U000027BF\U0001FA00-\U0001FA9F'
    r'\U0001F004\U0001F0CF\U00002702-\U000027B0]'
)

def in_code_block(text, pos):
    """Return True if pos is inside a code block."""
    before = text[:pos]
    # RST code blocks
    rst_starts = [m.end() for m in re.finditer(r'\.\. code-block::[^\n]*\n', before)]
    for start in reversed(rst_starts):
        block = text[start:]
        end_match = re.search(r'\n(?![ \t]|\n)', block)
        block_end = start + (end_match.start() if end_match else len(block))
        if start <= pos <= block_end:
            return True
    # Markdown fenced blocks
    fences = list(re.finditer(r'```', before))
    return len(fences) % 2 == 1

for f in sorted(DOCS.rglob("*.rst")) + sorted(DOCS.rglob("*.md")):
    if any(p in f.parts for p in EXCLUDE):
        continue
    text = f.read_text(errors="replace")
    rel = str(f.relative_to(DOCS))

    # Check emojis in prose
    for m in EMOJI_RE.finditer(text):
        if not in_code_block(text, m.start()):
            line = text[:m.start()].count('\n') + 1
            issues.append(f"EMOJI  {rel}:{line}  {repr(m.group())}")

    # Check wrong tool counts
    for bad in ["600+", "750+", "1200+", "10000+"]:
        if bad in text and "tools" in text[text.find(bad):text.find(bad)+20]:
            issues.append(f"COUNT  {rel}  contains '{bad} tools' (use '1000+')")

    # Check broken :doc: references
    for m in re.finditer(r':doc:`([^`]+)`', text):
        ref = m.group(1).lstrip('/')
        # Strip any display text (format: display <path>)
        if ' <' in ref:
            ref = re.search(r'<([^>]+)>', ref).group(1)
        base = DOCS / Path(ref.replace('/', '/'))
        candidates = [base.with_suffix('.rst'), base.with_suffix('.md'),
                      base / 'index.rst', base / 'index.md']
        if not any(c.exists() for c in candidates):
            line = text[:m.start()].count('\n') + 1
            issues.append(f"LINK   {rel}:{line}  broken :doc:`{ref}`")

# Check navbar in conf.py
conf = Path("docs/conf.py").read_text()
for bad_nav in ['"API"', '"API Keys"', '"Contribution"']:
    if bad_nav in conf:
        issues.append(f"NAV    conf.py  navbar contains {bad_nav}")
if "aiscientist.tools" not in conf:
    issues.append("NAV    conf.py  navbar missing aiscientist.tools link")

# Check per-platform page line counts
platform_dir = DOCS / "guide" / "building_ai_scientists"
for rst in platform_dir.glob("*.rst"):
    if rst.name in ("index.rst", "mcp_support.rst", "compact_mode.rst",
                    "mcpb_introduction.rst", "mcp_name_shortening.rst"):
        continue
    lines = rst.read_text().splitlines()
    if len(lines) > 15:
        issues.append(f"SIZE   guide/building_ai_scientists/{rst.name}  {len(lines)} lines (max 15)")

if issues:
    for i in sorted(issues):
        print(i)
    sys.exit(1)
else:
    print("Phase E clean")
EOF

フェーズ E で問題が報告された場合は、上記の「少ないほどよい」という判断ツリーに従ってください。フェーズ C に進む前に、すべての項目を修正します。


フェーズ C:ツール呼び出しチェック

python scripts/check_skill_tool_calls.py

src/tooluniverse/data/*.json からツールスキーマを読み込み、スキルの Markdown 内にあるすべての tools.X(...)、tu run X '{...}'、{"name": "X", "arguments": {...}} の呼び出しをチェックします。対象は、ツールで宣言されていない引数(ToolUniverse が拒否するか、有効な引数と混在している場合に黙って破棄するもの)、必須引数の不足、存在しないツール名です。これは静的チェックです。何もインスタンス化しません。また、これを必ず維持してください。一部のツールクラスは構築時に数 GB のデータセットを読み込むため、複数のツールを対象にライブ実行した際には 100 GB を超えました。意図的な誤用例には、呼び出し箇所またはその直上に WRONG、❌、# noqa: skill-call のいずれかを付けます。記載しようとしている戻り値の形式を確認する場合に限り、個々のツールを一度に 1 つずつライブ実行します。

よくある失敗:

エラー原因修正
KeyError: 'parameters'format="openai" を指定せずに tool_specification() を呼び出しているformat="openai" を追加する
OpenTargets の結果で KeyError: slice(...)dict をスライスしているresult['data']['disease']['associatedTargets']['rows'][:N] を使用する
TypeError: load_tools() got unexpected kwarguse_cache または cache_dirキーワード引数を削除する

フェーズ A:自動検証

python scripts/validate_documentation.py
# scripts/validate_documentation.py checks:
DEPRECATED_PATTERNS = [
    (r"python -m tooluniverse\.server", "tooluniverse-server"),
    (r"600\+?\s+tools", "1000+ tools"),
    (r"750\+?\s+tools", "1000+ tools"),
]

docs/、README.md、skills/ をスキャンします(非推奨のテキストを意図的に引用している docs/dev_docs/ とこのスキルはスキップします)。各一致箇所について file:line を出力し、一致箇所がある場合は終了コード 1 で終了します。意図的な記載には、同じ行に noqa: docs-validate を付けます。


フェーズ B:ToolUniverse 固有の監査

ナビゲーションの循環 — index.rst → quickstart → getting_started を手動でたどり、ループがないことを確認します。

ツール数 — どこでも「1000+ tools」に統一します。次を実行します:rg "[0-9]+\+?\s+(tools|integrations)" docs/ --no-filename | sort -u

自動生成ヘッダー — docs/tools/*_tools.rst と docs/api/*.rst は、.. AUTO-GENERATED で始まる必要があります。

CLI ドキュメント — pyproject.toml の [project.scripts] にある各エントリは、docs/reference/cli_tools.rst に記載されている必要があります。

環境変数 — src/ 内のすべての os.getenv("TOOLUNIVERSE_*") は、docs/reference/environment_variables.rst に記載されている必要があります。


RST コードブロック抽出器(重要)

隣接するブロックが結合されないよう、RST ブロックには常に re.DOTALL ではなく re.MULTILINE を使用します。

# correct
re.findall(r"\.\. code-block:: python\n((?:[ \t]+[^\n]*\n|[ \t]*\n)*)", text, re.MULTILINE)

# wrong — merges adjacent blocks
re.findall(r"\.\..*?code-block.*?python\n((?:[ \t]+.*\n|\n)*)", text, re.DOTALL)

検証チェックリスト

監査を完了する前に、すべての項目に合格する必要があります。一部のみの合格は認められません。

技術的な正確性:

  • Phase D のスキャンが 0 で終了する — 無効なメソッド呼び出しがない
  • python scripts/check_skill_tool_calls.py が 0 で終了する — スキルのコードブロックに不明なツールや引数がない
  • format="openai" を指定せずに spec['parameters'] を使用していない
  • 自動検証に合格する(HIGH の問題が 0 件)
  • pyproject.toml に記載されているすべての CLI が文書化されている
  • 循環ナビゲーションがない

シンプルさを重視(Apple スタイル):

  • Phase E のスキャンが 0 で終了する — 絵文字、誤った件数、リンク切れ、サイズの大きすぎるページがない
  • どこでも一貫して「1000+ tools」を使用している(600+、750+、10000+ などを使わない)
  • プラットフォームごとのセットアップページには、インストールリンク、MCP ガイドリンク、セットアッププロンプトのみがある(15 行以内)
  • サイト内に重複したセットアップ手順がない
  • ナビゲーションバーに「API」、「API Keys」、「Contribution」がなく、aiscientist.tools へのリンクがある
  • ホームページの「Explore More」グリッドのカード数が 4 以下
  • 概念やセクションが、複数の場所に同じ文言で掲載されていない
  • 4 件を超えるリンクを含む「See Also」/「Related」セクションがない

いずれかの項目に不合格の場合は、作業を中断して修正し、該当するフェーズを再実行して合格を確認してください。現在の項目に問題がなくなるまで、次の項目に進まないでください。


参照ファイル

  • API_REFERENCE.md — 有効なメソッドシグネチャ、誤ったメソッドの一覧、正しいパターン
  • DOCS_STRUCTURE.md — すべてのドキュメントファイルのファイルごとの監査状況
  • scripts/check_skill_tool_calls.py — Phase C の静的ツール呼び出しチェッカー

コメント