audit-discovery-symlinks
について
このスキルは、スキル、エージェント、チーム用のClaude Codeディスカバリーシンボリックリンクを監査および修復します。レジストリと.claude/ディレクトリを比較し、欠落、破損、または不要なシンボリックリンクを検出し、オプションで修復できます。新しいコンポーネントの追加後、リポジトリ変更後、またはスラッシュコマンドが失敗した際にご利用ください。
クイックインストール
Claude Code
推奨npx skills add pjt222/agent-almanac -a claude-code/plugin add https://github.com/pjt222/agent-almanacgit clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/audit-discovery-symlinksこのコマンドをClaude Codeにコピー&ペーストしてスキルをインストールします
ドキュメント
audit-discovery-symlinks
When Use
- After adding new skills, agents, teams to almanac
- After repository rename or move — may break absolute symlinks
- Slash commands or agents not found in Claude Code
- Periodic health check — catch drift between registries and discovery paths
- Onboarding new project — should discover shared almanac content
Do NOT use for creating initial symlink hub from scratch. See symlink-architecture guide for first-time setup.
Inputs
| Parameter | Type | Required | Description |
|---|---|---|---|
almanac_path | string | No | Absolute path to agent-almanac root. Auto-detected from .claude/ symlink targets or cwd if omitted |
scope | enum | No | project, global, or both (default: both) |
fix_mode | enum | No | report (default: audit only), auto (fix all safe issues), interactive (prompt before each fix) |
Steps
Step 1: Identify Almanac Path
Locate agent-almanac root directory.
# Auto-detect from current project's .claude/agents symlink
ALMANAC_PATH=$(readlink -f .claude/agents 2>/dev/null | sed 's|/agents$||')
# Fallback: check if cwd is the almanac
if [ -z "$ALMANAC_PATH" ] || [ ! -f "$ALMANAC_PATH/skills/_registry.yml" ]; then
if [ -f "skills/_registry.yml" ]; then
ALMANAC_PATH=$(pwd)
fi
fi
# Fallback: check global agents symlink
if [ -z "$ALMANAC_PATH" ] || [ ! -f "$ALMANAC_PATH/skills/_registry.yml" ]; then
ALMANAC_PATH=$(readlink -f ~/.claude/agents 2>/dev/null | sed 's|/agents$||')
fi
echo "Almanac path: $ALMANAC_PATH"
Got: ALMANAC_PATH points to directory containing skills/_registry.yml, agents/_registry.yml, teams/_registry.yml.
If fail: Auto-detection fails? Ask user for almanac_path input. Almanac root = directory with skills/, agents/, teams/, registries.
Step 2: Inventory Registries
Extract canonical lists of skills, agents, teams from registries.
# Count registered skills (entries with "- id:" under domain sections)
REGISTERED_SKILLS=$(grep '^ \{6\}- id:' "$ALMANAC_PATH/skills/_registry.yml" | awk '{print $3}' | sort)
REGISTERED_SKILL_COUNT=$(echo "$REGISTERED_SKILLS" | wc -l)
# Count registered agents
REGISTERED_AGENTS=$(grep '^ \{2\}- id:' "$ALMANAC_PATH/agents/_registry.yml" | awk '{print $3}' | sort)
REGISTERED_AGENT_COUNT=$(echo "$REGISTERED_AGENTS" | wc -l)
# Count registered teams
REGISTERED_TEAMS=$(grep '^ \{2\}- id:' "$ALMANAC_PATH/teams/_registry.yml" | awk '{print $3}' | sort)
REGISTERED_TEAM_COUNT=$(echo "$REGISTERED_TEAMS" | wc -l)
echo "Registered: $REGISTERED_SKILL_COUNT skills, $REGISTERED_AGENT_COUNT agents, $REGISTERED_TEAM_COUNT teams"
Got: Counts match total_skills, total_agents, total_teams values in each registry header.
If fail: Counts diverge from header totals? Registry out of sync. Note discrepancy in report, continue with actual - id: entries as source of truth.
Step 3: Audit Project-Level Symlinks
Check .claude/skills/*, .claude/agents, .claude/teams in current project directory.
PROJECT_CLAUDE=".claude"
# --- Skills ---
# Items on disk (excluding _template)
PROJECT_SKILLS=$(ls "$PROJECT_CLAUDE/skills/" 2>/dev/null | grep -v '^_template$' | sort)
PROJECT_SKILL_COUNT=$(echo "$PROJECT_SKILLS" | grep -c .)
# Missing: in registry but not in project .claude/skills/
MISSING_PROJECT_SKILLS=$(comm -23 <(echo "$REGISTERED_SKILLS") <(echo "$PROJECT_SKILLS"))
# Broken: symlink exists but target doesn't resolve
BROKEN_PROJECT_SKILLS=$(find "$PROJECT_CLAUDE/skills/" -maxdepth 1 -type l ! -exec test -e {} \; -printf '%f\n' 2>/dev/null | sort)
# Extraneous: in project but not in registry (and not external)
EXTRA_PROJECT_SKILLS=$(comm -13 <(echo "$REGISTERED_SKILLS") <(echo "$PROJECT_SKILLS"))
# --- Agents ---
if [ -L "$PROJECT_CLAUDE/agents" ] || [ -d "$PROJECT_CLAUDE/agents" ]; then
PROJECT_AGENT_STATUS="OK"
test -d "$PROJECT_CLAUDE/agents" || PROJECT_AGENT_STATUS="BROKEN"
PROJECT_AGENT_COUNT=$(ls "$PROJECT_CLAUDE/agents/"*.md 2>/dev/null | wc -l)
else
PROJECT_AGENT_STATUS="MISSING"
PROJECT_AGENT_COUNT=0
fi
# --- Teams ---
# Teams are NOT symlinked. TeamCreate uses ~/.claude/teams/ for runtime state.
# A .claude/teams symlink is a misconfiguration — warn if found.
if [ -L "$PROJECT_CLAUDE/teams" ]; then
PROJECT_TEAM_STATUS="MISCONFIGURED"
PROJECT_TEAM_COUNT=0
# Stale symlink — should be removed to avoid collision with TeamCreate
else
PROJECT_TEAM_STATUS="OK"
PROJECT_TEAM_COUNT=0
fi
Got: Zero missing, zero broken. Extraneous items classified and explained.
If fail: .claude/ doesn't exist? Project has no discovery setup. Note and skip to global audit.
Step 4: Audit Global Symlinks
Check ~/.claude/skills/* and ~/.claude/agents. Also check ~/.claude/teams NOT a symlink (should be absent or directory for TeamCreate runtime state).
GLOBAL_CLAUDE="$HOME/.claude"
# --- Skills ---
GLOBAL_SKILLS_ALL=$(ls "$GLOBAL_CLAUDE/skills/" 2>/dev/null | sort)
# Classify each entry: almanac vs external
ALMANAC_GLOBAL_SKILLS=""
EXTERNAL_GLOBAL_SKILLS=""
for item in $GLOBAL_SKILLS_ALL; do
target=$(readlink -f "$GLOBAL_CLAUDE/skills/$item" 2>/dev/null)
if [ -z "$target" ]; then
# Real directory (not a symlink) — external
EXTERNAL_GLOBAL_SKILLS="$EXTERNAL_GLOBAL_SKILLS $item"
elif echo "$target" | grep -q "^$ALMANAC_PATH"; then
ALMANAC_GLOBAL_SKILLS="$ALMANAC_GLOBAL_SKILLS $item"
else
EXTERNAL_GLOBAL_SKILLS="$EXTERNAL_GLOBAL_SKILLS $item"
fi
done
# Filter: _template is always extraneous for almanac content
ALMANAC_GLOBAL_SKILLS=$(echo "$ALMANAC_GLOBAL_SKILLS" | tr ' ' '\n' | grep -v '^_template$' | grep -v '^$' | sort)
# Missing: in registry but not in global almanac skills
MISSING_GLOBAL_SKILLS=$(comm -23 <(echo "$REGISTERED_SKILLS") <(echo "$ALMANAC_GLOBAL_SKILLS"))
# Broken: symlink exists but target doesn't resolve
BROKEN_GLOBAL_SKILLS=$(find "$GLOBAL_CLAUDE/skills/" -maxdepth 1 -type l ! -exec test -e {} \; -printf '%f\n' 2>/dev/null | sort)
# Stale almanac entries: in global almanac set but not in registry
STALE_GLOBAL_SKILLS=$(comm -13 <(echo "$REGISTERED_SKILLS") <(echo "$ALMANAC_GLOBAL_SKILLS"))
# --- Agents ---
if [ -L "$GLOBAL_CLAUDE/agents" ] || [ -d "$GLOBAL_CLAUDE/agents" ]; then
GLOBAL_AGENT_STATUS="OK"
test -d "$GLOBAL_CLAUDE/agents" || GLOBAL_AGENT_STATUS="BROKEN"
GLOBAL_AGENT_COUNT=$(ls "$GLOBAL_CLAUDE/agents/"*.md 2>/dev/null | wc -l)
else
GLOBAL_AGENT_STATUS="MISSING"
GLOBAL_AGENT_COUNT=0
fi
# --- Teams ---
# Teams are NOT symlinked. TeamCreate uses ~/.claude/teams/ for runtime state.
# A ~/.claude/teams symlink is a misconfiguration — warn if found.
if [ -L "$GLOBAL_CLAUDE/teams" ]; then
GLOBAL_TEAM_STATUS="MISCONFIGURED"
GLOBAL_TEAM_COUNT=0
# Stale symlink — should be removed to avoid collision with TeamCreate
else
GLOBAL_TEAM_STATUS="OK"
GLOBAL_TEAM_COUNT=0
fi
Got: Zero missing almanac skills, zero broken. External content (peon-ping, etc.) listed but not flagged as errors.
If fail: ~/.claude/ doesn't exist? Global hub not set up. See symlink-architecture guide for initial setup.
Step 5: Generate Audit Report
Produce summary table covering both layers.
# Discovery Symlink Audit Report
**Date**: YYYY-MM-DD
**Almanac**: <almanac_path>
**Scope**: both | project | global
## Summary
| Content | Registered | Project | Global (almanac) | Global (external) |
|---------|------------|---------|-------------------|-------------------|
| Skills | N | N | N | N |
| Agents | N | STATUS | STATUS | — |
| Teams | N | STATUS | STATUS | — |
## Issues
### Missing (registered but no symlink)
- Project skills: [list or "none"]
- Global skills: [list or "none"]
### Broken (symlink exists, target gone)
- Project: [list or "none"]
- Global: [list or "none"]
### Extraneous
- Stale almanac (in discovery but not registry): [list or "none"]
- _template in discovery path: [yes/no]
- External content (non-almanac): [list — informational only]
Got: Clear, actionable report. Zero issues = clean bill of health.
If fail: Report generation itself fails? Output raw counts and lists to console as fallback.
Step 6: Repair (Optional)
If fix_mode is auto or interactive, fix issues found.
6a. Create missing project symlinks:
for skill in $MISSING_PROJECT_SKILLS; do
ln -s "../../skills/$skill" "$PROJECT_CLAUDE/skills/$skill"
done
6b. Create missing global symlinks:
for skill in $MISSING_GLOBAL_SKILLS; do
ln -s "$ALMANAC_PATH/skills/$skill" "$GLOBAL_CLAUDE/skills/$skill"
done
6c. Remove broken symlinks:
# Project
for broken in $BROKEN_PROJECT_SKILLS; do
rm "$PROJECT_CLAUDE/skills/$broken"
done
# Global
for broken in $BROKEN_GLOBAL_SKILLS; do
rm "$GLOBAL_CLAUDE/skills/$broken"
done
6d. Remove stale almanac entries:
# Only remove items that target the almanac path but aren't in the registry
for stale in $STALE_GLOBAL_SKILLS; do
rm "$GLOBAL_CLAUDE/skills/$stale"
done
# Remove _template if present
rm -f "$GLOBAL_CLAUDE/skills/_template"
rm -f "$PROJECT_CLAUDE/skills/_template"
6e. Fix missing directory symlinks (agents/teams):
# Project agents
if [ "$PROJECT_AGENT_STATUS" = "MISSING" ]; then
ln -s ../agents "$PROJECT_CLAUDE/agents"
fi
# Project teams
if [ "$PROJECT_TEAM_STATUS" = "MISSING" ]; then
ln -s ../teams "$PROJECT_CLAUDE/teams"
fi
# Global agents
if [ "$GLOBAL_AGENT_STATUS" = "MISSING" ]; then
ln -s "$ALMANAC_PATH/agents" "$GLOBAL_CLAUDE/agents"
fi
# Global teams
if [ "$GLOBAL_TEAM_STATUS" = "MISSING" ]; then
ln -sf "$ALMANAC_PATH/teams" "$GLOBAL_CLAUDE/teams"
fi
Important: Never remove items classified as external. Belong to other projects (peon-ping). Preserve.
Got: All missing symlinks created, broken removed, stale almanac entries cleaned. External content untouched.
If fail: ln -s fails due to existing file/directory at target (e.g., empty directory instead of symlink)? Remove blocker first with rmdir (empty dirs) or flag for manual review (non-empty dirs).
Step 7: Verify
Re-run audit checks from Steps 3-4 to confirm repairs.
echo "=== Post-repair verification ==="
echo "Project skills: $(ls "$PROJECT_CLAUDE/skills/" 2>/dev/null | grep -v '^_template$' | wc -l)"
echo "Global skills (almanac): $(echo "$ALMANAC_GLOBAL_SKILLS" | wc -w)"
echo "Broken project: $(find "$PROJECT_CLAUDE/skills/" -maxdepth 1 -type l ! -exec test -e {} \; -print 2>/dev/null | wc -l)"
echo "Broken global: $(find "$GLOBAL_CLAUDE/skills/" -maxdepth 1 -type l ! -exec test -e {} \; -print 2>/dev/null | wc -l)"
echo "Project agents: $PROJECT_AGENT_STATUS ($PROJECT_AGENT_COUNT .md files)"
echo "Global agents: $GLOBAL_AGENT_STATUS ($GLOBAL_AGENT_COUNT .md files)"
echo "Project teams: $PROJECT_TEAM_STATUS ($PROJECT_TEAM_COUNT .md files)"
echo "Global teams: $GLOBAL_TEAM_STATUS ($GLOBAL_TEAM_COUNT .md files)"
Got: Zero missing, zero broken. Counts match registered totals (almanac content). External content listed separately.
If fail: Issues remain after repair? Report specific failures. Common causes: permission errors on ~/.claude/, NTFS path length limits on /mnt/ paths, non-empty directory blocking symlink creation.
Checks
- Almanac path correctly identified, contains all three registries
- Registry counts match
total_*header values (or discrepancy noted) - Project-level skills, agents, teams audited
- Global-level skills, agents, teams audited
- External content (non-almanac) identified and excluded from issue counts
-
_templateentries flagged as extraneous (never belongs in discovery paths) - Audit report generated with clear counts and actionable lists
- If
fix_modeisauto: all safe repairs applied, external content untouched - Post-repair verification confirms zero missing, zero broken
Pitfalls
-
Confusing external content with missing almanac content:
~/.claude/skills/may hold skills from other projects (peon-ping). Always check if symlink target under almanac path before classifying stale/extraneous. -
Removing external content: Never delete items not targeting almanac. Belong to other projects. Intentional.
-
Symlinking
_templatedirectories: Templates are scaffolding, not consumable content._templateshould never appear in.claude/skills/or.claude/agents/. Bulk sync scripts must skip it. -
Stale
.claude/teamssymlink:.claude/teamssymlink pointing to team definitions = misconfiguration. Claude Code'sTeamCreateuses~/.claude/teams/for runtime state (config.json, inboxes). Symlink to almanac'steams/= runtime artifacts written into git-tracked repo. Remove any.claude/teamssymlink at project or global level. -
Relative vs absolute paths: Project-level skill symlinks use relative paths (
../../skills/<name>). Global symlinks use absolute paths (/path/to/almanac/skills/<name>). Mixing breaks on moves. -
Registry header vs actual count:
total_skillsfield in registry header may be stale if someone added entries without updating count. Trust actual- id:entries, not header.
See Also
- repair-broken-references -- general broken link and reference repair
- tidy-project-structure -- project directory organization
- create-skill -- includes symlink creation for new skills (Step 13)
- create-agent -- includes discovery verification (Step 10)
- create-team -- team creation with registry integration
GitHub リポジトリ
関連スキル
content-collections
メタこのスキルは、Content Collections(Markdown/MDXファイルを型安全なデータコレクションに変換するTypeScriptファーストのツール)の本番環境でテストされた設定を提供します。Zodバリデーションによる型安全性を実現し、ブログ、ドキュメントサイト、コンテンツ重視のVite + Reactアプリケーション構築時にご利用ください。Viteプラグインの設定、MDXコンパイルから、デプロイ最適化、スキーマバリデーションまで、すべてを網羅しています。
polymarket
メタこのスキルは、開発者がPolymarket予測市場プラットフォームを活用したアプリケーション構築を可能にします。API統合による取引や市場データの取得に加え、WebSocketを介したリアルタイムデータストリーミングにより、ライブ取引や市場活動を監視できます。取引戦略の実装や、ライブ市場更新を処理するツールの作成にご利用ください。
creating-opencode-plugins
メタこのスキルは、開発者がコマンド、ファイル、LSP操作など25種類以上のイベントタイプにフックするOpenCodeプラグインを作成することを支援します。JavaScript/TypeScriptモジュール向けに、プラグイン構造、イベントAPI仕様、および実装パターンを提供します。カスタムイベント駆動ロジックでOpenCode AIアシスタントのライフサイクルをインターセプト、監視、または拡張する必要がある場合にご利用ください。
sglang
メタSGLangは、高性能なLLMサービングフレームワークであり、RadixAttentionプレフィックスキャッシュを活用したJSON、正規表現、エージェントワークフロー向けの高速で構造化された生成を特長とします。特にプレフィックスが繰り返されるタスクにおいて、大幅に高速な推論を実現し、複雑な構造化出力やマルチターン対話に最適です。制約付きデコードが必要な場合や、広範なプレフィックス共有を伴うアプリケーションを構築する場合は、vLLMなどの代替案ではなくSGLangを選択してください。
