Audit and fix skill accessibility across all 4 agents (Hermes, Claude Code, Codex CLI, Gemini CLI). Identifies gaps in symlink wiring, external_dirs, and per-repo routing.
Scanned 9/9/2026
Install to Claude Code
npx -y skills add vamseeachanta/workspace-hub --skill cross-agent-skill-audit --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Cross Agent Skill Audit?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/vamseeachanta-cross-agent-skill-audit-workspace-hub)More formats (shields.io, HTML) on the badges page.
---
name: cross-agent-skill-audit
version: 1.0.0
category: coordination
description: Audit and fix skill accessibility across all 4 agents (Hermes, Claude Code, Codex CLI, Gemini CLI). Identifies gaps in symlink wiring, external_dirs, and per-repo routing.
tags: [skills, audit, multi-agent, codex, gemini, hermes, claude-code, harness]
---
# Cross-Agent Skill Audit
## When to Use
- User reports a skill isn't visible to one or more agents
- After migrating skills between locations (~/.hermes/ vs .claude/)
- When adding a new repo to the workspace
- After hermes update or harness-update to verify nothing broke
## Architecture Overview
All 4 agents access skills through different mechanisms:
```
Hermes: external_dirs in ~/.hermes/config.yaml (reads 6 repos' .claude/skills/)
Claude Code: .claude/skills/ (native, on-demand via slash commands)
Codex CLI: .codex/skills/ → symlink → ../.claude/skills/
Gemini CLI: .gemini/skills/ → symlink → ../.claude/skills/
```
Per-repo: each repo that has agents must have `.codex/skills` and `.gemini/skills` symlinks pointing to `../../.claude/skills`.
## Audit Procedure
### Step 1: Count skills per agent
```bash
WS=/mnt/local-analysis/workspace-hub
# Claude Code (native .claude/skills/)
echo "CC: $(find -L $WS/.claude/skills -name 'SKILL.md' -not -path '*/_archive/*' | wc -l)"
# Codex (symlink → .claude/)
echo "Codex: $(find -L $WS/.codex/skills -name 'SKILL.md' -not -path '*/_archive/*' | wc -l)"
# Gemini (symlink → .claude/)
echo "Gemini: $(find -L $WS/.gemini/skills -name 'SKILL.md' -not -path '*/_archive/*' | wc -l)"
# Hermes (external_dirs)
grep -A7 'external_dirs' ~/.hermes/config.yaml | grep '.claude/skills' | wc -l
echo "(count of external_dirs paths)"
```
Expected: All three symlink agents should show the same count. A mismatch means broken symlink or real directory takeover.
### Step 2: Verify symlink integrity
```bash
# Check if .codex/skills is a symlink (NOT a real directory)
test -L $WS/.codex/skills && echo "OK: symlink" || echo "BROKEN: real dir or missing"
test -L $WS/.gemini/skills && echo "OK: symlink" || echo "BROKEN: real dir or missing"
# Check per-repo symlinks
for repo in CAD-DEVELOPMENTS digitalmodel worldenergydata achantas-data assetutilities; do
if [ -d "$WS/$repo/.codex" ]; then
target=$(readlink "$WS/$repo/.codex/skills" 2>/dev/null || echo "MISSING")
echo " $repo/.codex/skills → $target"
fi
done
```
### Step 3: Check external_dirs coverage
```bash
for d in $(grep 'external_dirs' ~/.hermes/config.yaml -A10 | grep '.claude/skills' | sed 's/.*- //'); do
count=$(find -L "$d" -name 'SKILL.md' -not -path '*/_archive/*' | wc -l 2>/dev/null)
label=$(basename $(dirname $(dirname "$d")))
echo " $label: $count skills"
done
```
### Step 4: Check for local-only skills
```bash
# Any skills left in ~/.hermes/skills/ not covered by external_dirs?
find ~/.hermes/skills -name 'SKILL.md' 2>/dev/null | while read f; do
echo " LOCAL ONLY: $f"
done
```
Expected: 0 results. Any local skills should be migrated to repo .claude/skills/.
## Common Fixes
### Fix 1: .codex/skills is a real directory instead of symlink
```bash
cd $WS
# Verify all 57 GSD skills exist in .claude/skills/ first
mv .codex/skills .codex/skills.bak
ln -s ../.claude/skills .codex/skills
rm -rf .codex/skills.bak # after verification
git add .codex/skills
git commit -m "fix(codex): replace .codex/skills real dir with symlink"
```
### Fix 2: Missing per-repo symlinks
```bash
cd $WS/GEMINI-REPO
rm -rf .codex/skills 2>/dev/null
rm -rf .gemini/skills 2>/dev/null
ln -s ../../.claude/skills .codex/skills
ln -s ../../.claude/skills .gemini/skills
git add .codex/skills .gemini/skills
git commit -m "feat(harness): add .codex/.gemini symlinks for GEMINI-REPO"
```
### Fix 3: Hermes external_dirs missing a repo
Edit `~/.hermes/config.yaml`:
```yaml
skills:
external_dirs:
- /path/to/repo/.claude/skills # ADD missing repo here
```
Then run: `scripts/_core/sync-agent-configs.sh`
### Fix 4: Skills in ~/.hermes/skills/ not migrated to repo
```bash
# Use the backfill script
bash scripts/hermes/backfill-skills-to-repo.sh --commit
# Manually: copy skill to repo .claude/skills/ then delete local copy
```
## Pitfalls
1. **find without -L doesn't follow symlinks**: Always use `find -L` when counting skills through `.codex/skills` or `.gemini/skills`. Plain `find` returns 0 for symlinked directories.
2. **Codex symlink takeover**: A common bug where `.codex/skills` somehow becomes a real directory (e.g., from a git checkout that dereferences symlinks). Always check with `test -L`.
3. **Per-repo vs workspace-hub access**: When Codex/Gemini work inside a sub-repo (e.g., CAD-DEVELOPMENTS/), their symlinks point to `../../.claude/skills` which is the sub-repo's local skills only. They do NOT automatically see workspace-hub canonical skills. This is by design to limit context budget.
4. **external_dirs path changes**: If workspace-hub moves to a different path, update `__WS_HUB_PATH__` in `config/agents/hermes/config.yaml.template` and re-run `sync-agent-configs.sh`.
5. **_archive directory**: The 2166 archived skills in workspace-hub `.claude/skills/` should NOT be counted. Always exclude with `-not -path '*/_archive/*'`.
6. **Empty category dirs in ~/.hermes/skills/**: After migration, empty dirs remain. Clean with: `find ~/.hermes/skills -mindepth 1 -maxdepth 1 -type d -empty -delete`
## Validation Checklist
After any change to the skill ecosystem:
- [ ] CC count = Codex count = Gemini count (workspace-hub baseline)
- [ ] .codex/skills is a symlink (test -L)
- [ ] .gemini/skills is a symlink (test -L)
- [ ] 0 skills in ~/.hermes/skills/ (find returns nothing)
- [ ] All 6 external_dirs paths exist in config.yaml
- [ ] hermes skills_list shows expected count
- [ ] skill_view <known-skill> works for both Hermes and CC
- [ ] git status clean (no unstaged symlink changes)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!