返回技能列表

audit-discovery-symlinks

pjt222
更新于 2 days ago
8 次查看
17
2
17
在 GitHub 上查看
开发ai

关于

This skill audits and repairs Claude Code discovery symlinks for skills, agents, and teams by comparing registry entries against the `.claude/` directory at both project and global levels. It detects missing, broken, and redundant symlinks while distinguishing between almanac content and external projects, with optional repair capabilities. Use it after adding new skills/agents, when slash commands stop working, or as a regular health check following repository changes.

快速安装

Claude Code

推荐
主要方式
npx skills add pjt222/agent-almanac -a claude-code
插件命令备选方式
/plugin add https://github.com/pjt222/agent-almanac
Git 克隆备选方式
git clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/audit-discovery-symlinks

在 Claude Code 中复制并粘贴此命令以安装该技能

技能文档

audit-discovery-symlinks(审计发现符号链接)

适用场景

  • 在向 almanac 添加新技能、代理或团队之后
  • 在仓库重命名或移动可能破坏绝对符号链接之后
  • 当 Claude Code 中找不到斜杠命令或代理时
  • 作为定期健康检查,捕捉注册表与发现路径之间的漂移
  • 当上线一个应该发现共享 almanac 内容的新项目时

请勿用于从零创建初始符号链接中心。请参阅 symlink-architecture 指南进行首次设置。

输入

参数类型必需描述
almanac_pathstringagent-almanac 根的绝对路径。若省略则从 .claude/ 符号链接目标或 cwd 自动检测
scopeenumprojectglobalboth(默认:both
fix_modeenumreport(默认:仅审计)、auto(修复所有安全问题)、interactive(每次修复前询问)

步骤

第 1 步:识别 Almanac 路径

定位 agent-almanac 根目录。

# 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"

预期结果: ALMANAC_PATH 指向包含 skills/_registry.ymlagents/_registry.ymlteams/_registry.yml 的目录。

失败处理: 若自动检测失败,请向用户询问 almanac_path 输入。almanac 根是包含 skills/agents/teams/ 及其注册表的目录。

第 2 步:清点注册表

从注册表提取技能、代理和团队的规范列表。

# 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"

预期结果: 计数与每个注册表头部中的 total_skillstotal_agentstotal_teams 值匹配。

失败处理: 若计数与头部总数不一致,注册表本身已不同步。在报告中标注差异,但继续以实际的 - id: 条目作为真相来源。

第 3 步:审计项目级符号链接

检查当前项目目录中的 .claude/skills/*.claude/agents.claude/teams

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

预期结果: 缺失为零、损坏为零。多余项已分类并解释。

失败处理:.claude/ 完全不存在,项目没有发现设置。记录此事并跳到全局审计。

第 4 步:审计全局符号链接

检查 ~/.claude/skills/*~/.claude/agents。同时检查 ~/.claude/teams 不是符号链接(应为缺失或为 TeamCreate 运行时状态准备的目录)。

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

预期结果: 缺失的 almanac 技能为零、损坏为零。外部内容(peon-ping 等)被列出但不标记为错误。

失败处理:~/.claude/ 不存在,全局中心未设置。请参阅 symlink-architecture 指南进行初始设置。

第 5 步:生成审计报告

产出涵盖两个层级的摘要表。

# 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]

预期结果: 清晰、可执行的报告。零问题意味着健康状况良好。

失败处理: 若报告生成本身失败,将原始计数和列表输出到控制台作为后备。

第 6 步:修复(可选)

fix_modeautointeractive,修复发现的问题。

6a. 创建缺失的项目符号链接:

for skill in $MISSING_PROJECT_SKILLS; do
  ln -s "../../skills/$skill" "$PROJECT_CLAUDE/skills/$skill"
done

6b. 创建缺失的全局符号链接:

for skill in $MISSING_GLOBAL_SKILLS; do
  ln -s "$ALMANAC_PATH/skills/$skill" "$GLOBAL_CLAUDE/skills/$skill"
done

6c. 移除损坏的符号链接:

# 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. 移除过时的 almanac 条目:

# 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. 修复缺失的目录符号链接(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

重要: 切勿移除分类为外部的项。它们属于其他项目(如 peon-ping),必须保留。

预期结果: 已创建所有缺失的符号链接、移除所有损坏的符号链接、清理所有过时的 almanac 条目。外部内容未被触动。

失败处理:ln -s 因目标路径存在文件/目录而失败(如空目录而非符号链接),先用 rmdir(空目录)移除阻塞物或标记以供手动审查(非空目录)。

第 7 步:验证

重新运行第 3-4 步的审计检查以确认修复。

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)"

预期结果: 缺失为零、损坏为零。计数与已注册总数匹配(对 almanac 内容)。外部内容单独列出。

失败处理: 若修复后仍有问题,报告具体故障。常见原因:~/.claude/ 上的权限错误、/mnt/ 路径上的 NTFS 路径长度限制,或非空目录阻塞符号链接创建。

验证清单

  • 正确识别 almanac 路径,并包含所有三个注册表
  • 注册表计数匹配 total_* 头部值(或已记录差异)
  • 已审计项目级技能、代理和团队
  • 已审计全局级技能、代理和团队
  • 已识别外部内容(非 almanac)并将其排除在问题计数之外
  • _template 条目已标记为多余(绝不属于发现路径)
  • 已生成带有清晰计数和可执行列表的审计报告
  • fix_modeauto:已应用所有安全修复,外部内容未被触动
  • 修复后验证确认缺失为零、损坏为零

常见问题

  1. 将外部内容与缺失的 almanac 内容混淆~/.claude/skills/ 可能包含其他项目的技能(如 peon-ping)。在将符号链接归类为过时或多余之前,始终检查目标是否在 almanac 路径下。

  2. 移除外部内容:切勿删除不指向 almanac 的项。它们属于其他项目,是有意为之。

  3. 符号链接 _template 目录:模板是脚手架,不是可消费内容。_template 目录绝不应出现在 .claude/skills/.claude/agents/ 中。批量同步脚本必须显式跳过它。

  4. 过时的 .claude/teams 符号链接:指向团队定义的 .claude/teams 符号链接是错误配置。Claude Code 的 TeamCreate 使用 ~/.claude/teams/ 作为运行时状态(config.json、收件箱)。若此路径是指向 almanac 的 teams/ 目录的符号链接,运行时工件将被写入 git 跟踪的仓库。移除在项目或全局级别找到的任何 .claude/teams 符号链接。

  5. 相对 vs 绝对路径:项目级技能符号链接使用相对路径(../../skills/<name>)。全局符号链接使用绝对路径(/path/to/almanac/skills/<name>)。混用这些模式会在移动时导致破坏。

  6. 注册表头部 vs 实际计数:注册表头部中的 total_skills 字段可能过时(若有人添加条目而未更新计数)。信任实际的 - id: 条目,而非头部。

相关技能

GitHub 仓库

pjt222/agent-almanac
路径: i18n/zh-CN/skills/audit-discovery-symlinks
0
agentsagentskillsai-assisted-developmentclaude-codeskillsteams

相关推荐技能

qmd

开发

这是一个本地搜索和索引的CLI工具,支持BM25、向量搜索和重排序功能。开发者可以用它快速索引本地文件(如Markdown文档)并进行混合搜索,特别适合代码库或文档的本地检索。它还提供MCP模式,能轻松集成到Claude开发环境中使用。

查看技能

subagent-driven-development

开发

该Skill用于在当前会话中执行包含独立任务的实施计划,它会为每个任务分派一个全新的子代理并在任务间进行代码审查。这种"全新子代理+任务间审查"的模式既能保障代码质量,又能实现快速迭代。适合需要在当前会话中连续执行独立任务,并希望在每个任务后都有质量把关的开发场景。

查看技能

mcporter

开发

mcporter Skill 让开发者能在Claude中直接管理和调用MCP服务器。它支持列出可用服务器、调用工具、处理OAuth认证以及管理服务器守护进程。开发者可以通过命令行式交互快速执行`mcporter list`查看服务器,或使用`mcporter call`直接调用工具,简化了MCP工作流程。

查看技能

adk-deployment-specialist

开发

这是一个用于部署和编排Google Vertex AI ADK智能体的Claude Skill,专为构建生产级多智能体系统而设计。它支持通过A2A协议进行智能体通信,提供代码执行沙箱和记忆库功能,并能处理智能体发现与任务提交。当开发者需要部署ADK智能体或编排多智能体协作时,可使用此Skill来简化Vertex AI Agent Engine的部署流程。

查看技能