Compare Japanese NLP resources for: "$ARGUMENTS" across a few criteria, as a table.
If $ARGUMENTS is empty or blank, stop immediately and output:
Usage: /awesome-japanese-nlp-resources:compare <tool-name | topic>
Examples:
/awesome-japanese-nlp-resources:compare mecab
/awesome-japanese-nlp-resources:compare 形態素解析
/awesome-japanese-nlp-resources:compare japanese sentence embedding models
/awesome-japanese-nlp-resources:compare OCR
Pass a tool name (to compare it against its closest alternatives) or a topic/function (to compare the leading options for that task).
---
使い方: /awesome-japanese-nlp-resources:compare <ツール名 | トピック>
例:
/awesome-japanese-nlp-resources:compare mecab
/awesome-japanese-nlp-resources:compare 形態素解析
/awesome-japanese-nlp-resources:compare 日本語 文埋め込み モデル
/awesome-japanese-nlp-resources:compare OCR
比較したいツール名(その代替と比較)、またはトピック/機能名(その分野の主要な選択肢を比較)を引数に指定してください。
Do not proceed if $ARGUMENTS is empty. Unlike discover, this skill has no empty-argument default — a comparison needs something to compare.
$ARGUMENTS is: "$ARGUMENTS"
Seed mode — names ONE specific existing tool/library/model (a full GitHub/Hugging Face URL, owner/repo, or a bare tool name, e.g. mecab, fugashi). Pass it through as SEED and proceed to Step 3 in seed mode — the comparison set will be the seed plus its closest peers.
Topic mode — a descriptive/functional phrase with no single specific name (e.g. 形態素解析, japanese sentence embedding models, OCR). Proceed to Step 3 in topic mode — the comparison set will be the leading local matches for the topic.
RESOURCES_PATH="${CLAUDE_PLUGIN_ROOT}/data/resources.json"
[ -f "$RESOURCES_PATH" ] || RESOURCES_PATH="$(find "${HOME}/.claude/plugins" -type f -name resources.json 2>/dev/null | grep "awesome-japanese-nlp-resources/" | head -1)"
echo "RESOURCES_PATH=$RESOURCES_PATH"
Do NOT use the Read tool on resources.json. Run one of the two scripts below, substituting RESOURCES_PATH (Step 2) and, for seed mode, SEED (from Step 1).
Seed mode — locate the seed and score peers by shared category, shared semantic labels, and shared description tokens (IDF-weighted):
python3 << 'EOF'
import json, re, math
from collections import Counter
RESOURCES_PATH = "RESOURCES_PATH" # from Step 2
SEED_RAW = "SEED" # from Step 1
with open(RESOURCES_PATH) as f:
data = json.load(f)
N = len(data)
STOP = {
"the","and","for","with","that","this","from","into","your","you","are","was",
"japanese","nlp","python","library","tool","tools","text","based","using","use",
"used","language","data","model","models","repository","repo","support","simple",
"fast","easy","also","can","via","etc","https","http","github","com","www","org",
"not","but","all","any","other","such","more","most","than","its","each","which",
}
def norm_url(u): return (u or "").lower().rstrip("/")
def subs_of(it): return set(t.strip().lower() for t in (it.get("s") or []))
def family(c): return (c or "").split("(")[0].strip().lower()
def toks(text):
return set(w for w in re.findall(r"[a-z0-9]+", (text or "").lower())
if len(w) >= 4 and w not in STOP)
seed = SEED_RAW.strip().lower().rstrip("/")
gh_m = re.search(r"github\.com/([^/#?]+/[^/#?]+)", seed)
hf_m = re.search(r"huggingface\.co/(?:datasets/)?([^/#?]+/[^/#?]+)", seed)
slug = (gh_m or hf_m).group(1) if (gh_m or hf_m) else (seed if seed.count("/") == 1 else None)
basename = seed.split("/")[-1]
def find_matches():
exact = [x for x in data if norm_url(x["u"]) == seed]
if exact: return exact, "exact URL"
if slug:
sm = [x for x in data if norm_url(x["u"]).endswith("/" + slug)]
if sm: return sm, "owner/repo"
return [], None
nm = [x for x in data if x["n"].lower() == basename]
if nm: return nm, "name"
loose = [x for x in data if basename and (basename in x["n"].lower() or ("/" + basename) in norm_url(x["u"]))]
if loose: return loose, "loose substring"
return [], None
matches, how = find_matches()
matches.sort(key=lambda x: -(max(x.get("ns") or 0, x.get("nd") or 0)))
seed_item = matches[0] if matches else None
if not seed_item:
print("SEED_NOT_FOUND")
raise SystemExit
print(f"SEED_FOUND via {how}: {seed_item['n']}")
print(f" url={seed_item['u']} c={seed_item['c']}")
print(f" d={seed_item.get('d','')[:200]}")
print()
sub_df, tok_df = Counter(), Counter()
for x in data:
for s in subs_of(x): sub_df[s] += 1
for t in toks((x.get("d") or "") + " " + x["n"] + " " + " ".join(x.get("s") or [])): tok_df[t] += 1
def idf_sub(l): return max(0.0, math.log(N / sub_df.get(l, 1)) - 1.5)
def idf_tok(t): return max(0.0, math.log(N / tok_df.get(t, 1)) - 1.5)
seed_cat = seed_item["c"]; seed_fam = family(seed_cat)
seed_subs = subs_of(seed_item)
seed_tok = toks((seed_item.get("d") or "") + " " + seed_item["n"] + " " + " ".join(seed_item.get("s") or []))
seed_name = seed_item["n"].lower()
seed_urls = {norm_url(seed_item["u"])} | {norm_url(x["u"]) for x in matches if x["n"].lower() == seed_name}
results = []
for x in data:
if x.get("status") == "not_found" or norm_url(x["u"]) in seed_urls:
continue
score = 0.0
if x["c"] == seed_cat: score += 10
elif family(x["c"]) == seed_fam: score += 5
sh_subs = seed_subs & subs_of(x)
score += 3.0 * sum(idf_sub(l) for l in sh_subs)
sh_tok = seed_tok & toks((x.get("d") or "") + " " + x["n"] + " " + " ".join(x.get("s") or []))
score += 1.5 * sum(idf_tok(t) for t in sh_tok)
if score < 8.0:
continue
pop = max(x.get("ns") or 0, x.get("nd") or 0)
results.append((score + 0.5 * pop, x))
results.sort(key=lambda r: -r[0])
print(f"=== CANDIDATES ({len(results)} peers found; seed + top 6 shown) ===")
print(f"[seed] n={seed_item['n']} u={seed_item['u']} c={seed_item['c']} d={seed_item.get('d','')[:150]}")
for score, x in results[:6]:
print(f"score={score:.1f} n={x['n']} u={x['u']} c={x['c']} d={x.get('d','')[:150]}")
EOF
Topic mode — score by keyword match (3–5 stems from Step 1, same conventions as search):
python3 << 'EOF'
import json
with open("RESOURCES_PATH") as f: # from Step 2
data = json.load(f)
keywords = ["keyword1", "keyword2", "keyword3"] # short stems, from Step 1
results = []
for item in data:
if item.get("status") == "not_found":
continue
n = item.get("n", "").lower(); d = item.get("d", "").lower()
s = " ".join(item.get("s") or []).lower(); c = item.get("c", "").lower()
al = " ".join(item.get("al") or []).lower()
text_score = 0
for kw in keywords:
kw = kw.lower()
if n == kw: text_score += 20
elif kw in n: text_score += 10
if kw in d: text_score += 5
if kw in s: text_score += 3
if kw in c: text_score += 2
if kw in al: text_score += 10
if text_score < 8:
continue
ns = item.get("ns") or 0; nd = item.get("nd") or 0
results.append((text_score + max(ns, nd) * 2.5, item))
results.sort(key=lambda x: -x[0])
print(f"=== CANDIDATES ({len(results)} matches; top 6 shown) ===")
for combined, item in results[:6]:
print(f"score={combined:.1f} n={item['n']} u={item['u']} c={item['c']} d={item.get('d','')[:150]}")
EOF
From Step 3's output, pick 3–6 candidates for the table:
mecab and 3 thin wrappers around mecab as if they were independent options — pick the one or two that matter, plus other real alternatives).If fewer than 3 solid local candidates exist, run 2–3 WebSearch queries (<topic-en> japanese library, japanese <topic-en> alternatives, <topic-en> japanese huggingface) to find 1–3 more well-known options. You don't need to filter these against the dataset the way discover does — the goal here is just enough real, comparable candidates for a meaningful table, not a completeness audit.
If, even after this, fewer than 2 comparable resources exist, stop and say so — a 1-row table isn't a comparison. Suggest /awesome-japanese-nlp-resources:search "$ARGUMENTS" instead.
Pick 3–5 axes that a practitioner would actually use to decide between these specific candidates — do not reuse a generic checklist. Good axes:
For each candidate × axis, decide:
Ground every rating in evidence:
d/d_ja/s/st/lc fields as a first signal.WebFetch url="https://github.com/<owner>/<repo>" prompt="Extract as JSON: license, key features relevant to <the chosen axes>, install/setup complexity, and any explicit limitations mentioned. If a field is unavailable, set it to null."
Language detection rule:
$ARGUMENTS contains Japanese characters (hiragana / katakana / kanji) → Japanese
## Comparison: "$ARGUMENTS"
| Resource | <Axis 1> | <Axis 2> | <Axis 3> | <Axis 4> |
|---|---|---|---|---|
| [name](url) | ○ | △ | ○ | ✕ |
| [name](url) | ○ | ○ | △ | ○ |
○ = clearly supports / strong · △ = partial or unverified · ✕ = does not support / weak
**Notes:**
- [name]: one-line justification for any △ or ✕ rating that isn't self-evident.
- [name]: ...
**Recommendation:**
- If <priority A> matters most: [name](url) — why.
- If <priority B> matters most: [name](url) — why.
Sources (if WebFetch/WebSearch used):
- [Title](https://...)
Japanese output template: mirror the structure with ## 比較: "$ARGUMENTS", **注記:**, **おすすめ:**, keeping the ○/△/✕ symbols and legend as-is (they're already language-neutral).
Rules:
/awesome-japanese-nlp-resources:search or /awesome-japanese-nlp-resources:discover).Sources: is mandatory.