| name | check-sync |
| description | Detect drift between CAB plugin extensions (source of truth) and deployed global ~/.claude/ extensions. Three failure modes detected: content drift, scope-shadowing across local→user→plugin layers (LL-27), AND type-shadowing at the same scope when commands and skills share names (LL-32). Triggers: sync check, plugin drift, shadow scan, type collision, deploy alignment, before pushing CAB changes, after global config edits. |
| argument-hint | Scope: agents/skills/commands; flags: --shadow-only, --drift-only, --type-shadow-only |
| allowed-tools | Read, Bash, Grep, Glob |
Plugin ↔ Global Sync Check
Purpose
CAB's distributable plugin extensions can become out of sync with what's
actually deployed under ~/.claude/. Three failure modes:
- Drift — file content differs between plugin and global copy
(one was updated, the other wasn't)
- Scope-shadowing (LL-27) — a same-named file exists at the higher-precedence
global layer (
~/.claude/agents/<name>.md), silently overriding the
plugin's version due to CC's resolution order
(local → user → plugin)
- Type-shadowing (LL-32) — at the SAME scope, a command file
(
commands/<name>.md) and a skill (skills/<name>/SKILL.md) share the
same name, causing the resolver to route to the command shim instead of
the skill body. Contradicts DP2 line 69 ("skills win when both exist").
Distinct from LL-27 (cross-scope) — type-shadowing is at the same scope.
This skill detects all three — even a byte-identical scope-shadow is a
future-drift risk; type-shadows always cause invocation routing surprises
regardless of byte-identity.
When to Invoke
- After making changes to CAB plugin extensions, before pushing
- Periodically (weekly) as a hygiene check
- After editing
~/.claude/ directly, to catch accidental shadowing
- Before publishing a new CAB plugin version
Protocol
Step 1: Discover Paired Files
| CAB plugin location | Global equivalent |
|---|
agents/*.md | ~/.claude/agents/*.md |
skills/*/SKILL.md | ~/.claude/skills/*/SKILL.md |
commands/*.md | ~/.claude/commands/*.md |
If $ARGUMENTS is agents, skills, or commands, scope to that type.
Step 2: Drift Comparison
for cab_path in <plugin>; do
global_path="$HOME/.claude/<corresponding-path>"
[ -f "$global_path" ] || continue
diff -q "$cab_path" "$global_path" >/dev/null || echo "DRIFT: $cab_path"
done
Skip in --shadow-only mode.
Step 3: Scope-Shadow Scan (LL-27 enforcement)
For each agent/skill/command in CAB plugin (or any other enabled plugin
when scope expanded), check whether a same-named file exists under
~/.claude/. Any match is a SHADOW regardless of content:
for cab_agent in agents/*.md; do
name=$(basename "$cab_agent")
global="$HOME/.claude/agents/$name"
if [ -f "$global" ]; then
if cmp -s "$cab_agent" "$global"; then
echo "SHADOW (byte-identical, future-drift risk): $name"
else
echo "SHADOW (content diverged, LL-27 active): $name"
fi
fi
done
For other enabled plugins: read ~/.claude/settings.json for
enabledPlugins, walk each plugin's extension directories, repeat the
same-name check. Narrow to CAB-only if enumeration is unavailable.
Skip in --drift-only mode (legacy behavior).
Step 3b: Type-Shadow Scan (LL-32 enforcement; same-scope collision)
Detect command↔skill name collisions at the same scope. When commands/<name>.md and skills/<name>/SKILL.md coexist, the Skill-tool resolver and slash-invocation surface route to the command shim regardless of DP2 "skills win" precedence — empirically observed in Session 42.
for cmd_path in commands/*.md; do
[ -f "$cmd_path" ] || continue
cmd_name=$(basename "$cmd_path" .md)
echo "$cmd_path" | grep -q "/_archive/" && continue
skill_path="skills/$cmd_name/SKILL.md"
if [ -f "$skill_path" ]; then
echo "TYPE-SHADOW (same-scope collision, LL-32): $cmd_name (commands/$cmd_name.md ↔ skills/$cmd_name/SKILL.md)"
fi
done
for cmd_path in "$HOME/.claude/commands/"*.md; do
[ -f "$cmd_path" ] || continue
cmd_name=$(basename "$cmd_path" .md)
skill_path="$HOME/.claude/skills/$cmd_name/SKILL.md"
if [ -f "$skill_path" ]; then
echo "TYPE-SHADOW (global scope, LL-32): $cmd_name"
fi
done
Skip in --drift-only or --shadow-only modes (these target drift / scope-shadow only).
Step 4: Report
── SYNC CHECK ─────────────────────────────────
✅ In sync (N files)
agents/orchestrator.md
...
⚠️ Drift detected (N files)
skills/analyze-architecture/SKILL.md
CAB newer: 2026-04-25 | Global: 2026-04-22
Lines changed: +12 -3
⚠️ SCOPE-SHADOW DETECTED — LL-27 (N files)
agents/orchestrator.md
Plugin copy: <cab-root>/agents/orchestrator.md
Shadow copy: ~/.claude/agents/orchestrator.md (byte-identical)
Risk: global copy frozen at snapshot; plugin updates silently blocked
⚠️ TYPE-SHADOW DETECTED — LL-32 (N collisions)
execute-task
Command path: commands/execute-task.md
Skill path: skills/execute-task/SKILL.md
Risk: Skill-tool resolver routes to command shim instead of skill body
(contradicts DP2 line 69 "skills win when both exist")
Fix: archive the command shim (e.g., commands/_archive/) or migrate
shim logic into skill body
❌ Missing from global (N files)
skills/close-session/SKILL.md
❌ Extra in global (not in CAB) (N files)
skills/strategy-framework/SKILL.md
───────────────────────────────────────────────
Step 5: Recommend Actions
Per finding:
| Finding | Recommended action |
|---|
| CAB newer (no shadow) | cp <cab-path> <global-path> to deploy |
| Global newer (no shadow) | Review — global has changes not in CAB; merge or overwrite |
| SCOPE-SHADOW byte-identical (LL-27) | rm <global-path> — plugin version takes over, receives future updates |
| SCOPE-SHADOW content diverged (LL-27) | Confirm intent: documented override? If not, remove shadow + backport wanted deltas. If yes, document rationale in CAB CLAUDE.md Extension Registry |
| TYPE-SHADOW (LL-32) | Archive the command shim (git mv commands/<name>.md commands/_archive/) — _archive/ is gitignored per .gitignore global rule. Or, if the command has unique logic the skill lacks, migrate that logic into the skill body before archive |
| Missing from global | Deploy new extension if intended |
| Extra in global | Not CAB-managed; ignore or integrate into CAB |
Arguments
- (none): full sync check (drift + scope-shadow + type-shadow across all extension types)
agents / skills / commands: scope to that type
--shadow-only: skip drift report; both scope-shadow (LL-27) + type-shadow (LL-32) scans
--scope-shadow-only: LL-27 cross-scope collision scan only
--type-shadow-only: LL-32 same-scope command↔skill collision scan only
--drift-only: skip both shadow scans (legacy behavior)
Verification
This skill is working correctly when:
- Content drift, scope-shadowing (LL-27), AND type-shadowing (LL-32) are all detected
independently (one type of finding doesn't mask another)
- Byte-identical scope-shadows are still flagged (frozen-snapshot risk)
- Type-shadows flag any same-name command↔skill pair regardless of byte-identity (resolver-routing risk is independent of file content)
- Recommendations are file-specific and command-ready
(
rm <exact-path>, git mv <cmd> commands/_archive/, not "remove shadows")
- Excludes
settings.local.json and CLAUDE.local.md (personal, not synced)
- Excludes
commands/_archive/** paths from type-shadow detection (archived shims are intentional, not active collisions)
Integration Points
commands/sync-check.md — shim trigger preserving /cab:sync-check
audit-workspace skill — folds shadow-scan into /validate --cab-audit
(UXL-013 coupling)
knowledge/operational-patterns/multi-agent/agent-resolution.md —
full precedence + shadowing reference
notes/lessons-learned.md LL-27 — failure mode this skill enforces against
commit-push-pr skill — natural follow-on after fixing drift
See Also
knowledge/operational-patterns/sync-protocol.md — full sync protocol
- LL-27 — plugin↔global name-collision shadowing (root failure mode)