短答案
.claude/skills 已有內容時,不要整棵替換。只替需要共用的 Skill
建立 Link:
.agents/skills/ # 可攜 Skill 的來源
.claude/skills/<portable-skill> # 指向來源的 Junction / symlink
.claude/skills/<claude-only> # Claude 專屬實體 Skill
AGENTS.md # 共用專案規則
CLAUDE.md # @AGENTS.md + Claude-only 補充
只有兩邊內容完全同質時,才考慮整棵 Skills Junction。規則檔優先用
@AGENTS.md;Hard Link 留給固定在 Windows/NTFS、而且兩個檔名必須永遠
同內容的環境。
Claude Code 沒有掃 .agents/skills
Agent Skills 規格定義 SKILL.md 的結構,各個 client 仍可決定安裝位置。
許多工具採用 .agents/skills;Claude Code 的專案路徑則是
.claude/skills/<skill-name>/SKILL.md。檔案可讀,不等於原生 discovery
會找到它。
內容留一份
.agents/skills 保存可攜版本,避免兩份 SKILL.md 漂移。
補原生路徑
Link 把同一份內容露出在 .claude/skills,不靠模型臨時搜尋。
回到 Claude 測
檢查 slash autocomplete、auto-invocation 與 /context,不只看檔案存在。
mapping 已經存在,但目標是實體目錄
以下以專案根目錄內的 Link bootstrap 為例。腳本可用相對路徑定義
.claude\skills → .agents\skills,並讓
CLAUDE.md、GEMINI.md 共用來源
AGENTS.md。若目標已經是實體目錄,就不能直接覆蓋。
$directoryLinks = [ordered]@{
".claude\skills" = ".agents\skills"
}
$instructionLinks = [ordered]@{
"AGENTS.md" = "AGENTS.md"
"CLAUDE.md" = "AGENTS.md"
"GEMINI.md" = "AGENTS.md"
}
發布文件可使用的中性情境
- 所有路徑都以目前專案根目錄為基準。
.agents\skills與.claude\skills目前都是實體目錄。- 兩邊可能各有獨有 Skill,也可能存在同名但內容不同的檔案。
- 完成內容比對前,不刪除、不搬移,也不覆蓋任何既有目錄。
- bootstrap 從目前專案根目錄解析來源與目標。
- 建立 Link 前,先檢查目標是否已存在以及它的
LinkType。 - 目標若是實體目錄,腳本應停止或跳過,交由人工先比較內容。
Link 方案沒有壞。真正的前置工作,是先拆清楚兩邊哪些 Skill 可共用、哪些只能留給
Claude。直接刪除 .claude\skills 可能把 Claude-only Skill 一併移除。
動手前,先確認 .claude\skills 是什麼
- 以下命令都在專案根目錄執行。
.agents\skills必須存在,每個 Skill 目錄內要有SKILL.md。- 查清楚
.claude\skills是實體目錄、Junction,還是 Symbolic Link。 - Hard Link 的來源與目標必須位於同一個 volume。
- Junction 可跨本機 volume,但不能指向映射的網路磁碟。
$repoRoot = (Resolve-Path ".").Path
$agentsSkills = Join-Path $repoRoot ".agents\skills"
$claudeSkills = Join-Path $repoRoot ".claude\skills"
if (-not (Test-Path -LiteralPath $agentsSkills)) {
throw "找不到 Skill 來源目錄:$agentsSkills"
}
Get-Item -LiteralPath $agentsSkills -Force |
Select-Object FullName, Attributes, LinkType, Target
if (Test-Path -LiteralPath $claudeSkills) {
Get-Item -LiteralPath $claudeSkills -Force |
Select-Object FullName, Attributes, LinkType, Target
}
ReparsePoint。
.claude\skills
是實體目錄,先比較內容。兩種接法怎麼選
整個目錄做 Junction
適合所有 Skill 都能共用,而且 .claude\skills 尚不存在的專案。
- 結構簡單。
- 無法保留 Claude-only Skill。
- 建立後仍要到 Claude Code 裡驗收。
只連需要共用的 Skill
保留實體 .claude\skills,只替可攜 Skill 建立 Link。
- 可攜與 Claude-only Skill 能並存。
- 可以只拿一個 Skill 試跑。
- 需要時再用 bootstrap script 重建。
| 現況 | 建議 |
|---|---|
| 兩邊 Skills 完全同質 | 整棵 Junction |
| 已有 Claude-only Skill | 逐 Skill Junction/symlink |
| 跨 Windows、macOS、Linux | 逐 Skill Symbolic Link + bootstrap script |
| Cloud session 或 remote container | 提交 project Skill 或安裝 plugin;不依賴本機外部 Link |
接法 A:整個 Skills 目錄做 Junction
適用條件:.claude\skills 尚不存在,且不需要 Claude-only
Skills。
$repoRoot = (Resolve-Path ".").Path
$source = Join-Path $repoRoot ".agents\skills"
$claudeDir = Join-Path $repoRoot ".claude"
$target = Join-Path $claudeDir "skills"
if (-not (Test-Path -LiteralPath $source)) {
throw "找不到來源:$source"
}
New-Item -ItemType Directory -Path $claudeDir -Force | Out-Null
if (Test-Path -LiteralPath $target) {
throw "目標已存在,未建立 Link:$target"
}
New-Item `
-ItemType Junction `
-Path $target `
-Target (Resolve-Path $source) |
Select-Object FullName, LinkType, Target
看到這些才算建立成功:.claude\skills → .agents\skills,
輸出同時顯示 LinkType = Junction 與正確 target。
接法 B:只連需要共用的 Skill
.claude 已有內容時,從一個可攜 Skill 開始最安全。這個目錄之外的設定與
Claude-only Skills 都不會被碰到。
$repoRoot = (Resolve-Path ".").Path
$skillName = "my-skill"
$source = Join-Path $repoRoot ".agents\skills\$skillName"
$claudeSkills = Join-Path $repoRoot ".claude\skills"
$target = Join-Path $claudeSkills $skillName
if (-not (Test-Path -LiteralPath (Join-Path $source "SKILL.md"))) {
throw "來源不是有效 Skill:$source"
}
New-Item -ItemType Directory -Path $claudeSkills -Force | Out-Null
if (Test-Path -LiteralPath $target) {
throw "Claude Skill entry 已存在,未覆蓋:$target"
}
New-Item `
-ItemType Junction `
-Path $target `
-Target (Resolve-Path $source) |
Select-Object FullName, LinkType, Target
Windows 已開啟 Developer Mode,或目前 shell 具備 symlink 權限時,也可以建立 Symbolic Link:
New-Item `
-ItemType SymbolicLink `
-Path $target `
-Target (Resolve-Path $source)
.claude\skills\my-skill。
SKILL.md,其他 Skills 未變。
SKILL.md、target 已存在或 symlink 權限不足。
規則檔不必再複製一份
@AGENTS.md import
AGENTS.md 繼續當共用來源,CLAUDE.md 只放 import
與 Claude-only 補充。跨平台,也沒有同 volume 限制。
Hard Link
只適合固定 Windows/NTFS、同一 volume,而且兩個檔名永遠必須同內容的環境。
方案 A:薄 CLAUDE.md import
@AGENTS.md
## Claude Code
- 把只適用 Claude Code 的補充規則放在這裡。
方案 B:以 Hard Link 共用規則檔
$repoRoot = (Resolve-Path ".").Path
$agentsFile = Join-Path $repoRoot "AGENTS.md"
$claudeFile = Join-Path $repoRoot "CLAUDE.md"
if (-not (Test-Path -LiteralPath $agentsFile)) {
throw "找不到 AGENTS.md 來源檔"
}
if (Test-Path -LiteralPath $claudeFile) {
throw "CLAUDE.md 已存在,未建立 Hard Link"
}
New-Item `
-ItemType HardLink `
-Path $claudeFile `
-Target $agentsFile
Hard Link 建立後,兩個檔名指向同一個檔案實體。從 CLAUDE.md
編輯也會改到 AGENTS.md;需要 Claude-only 內容時改用 import。
驗收要看 Link 身分,也要看內容
1. Link 型態與 target
Get-Item -LiteralPath ".claude\skills\my-skill" -Force |
Select-Object FullName, Attributes, LinkType, Target
預期 Attributes 包含 ReparsePoint,LinkType
為 Junction 或 SymbolicLink,且 Target
指向預期來源。
2. Entrypoint 與 SHA-256
Test-Path -LiteralPath ".claude\skills\my-skill\SKILL.md"
Get-FileHash ".agents\skills\my-skill\SKILL.md"
Get-FileHash ".claude\skills\my-skill\SKILL.md"
Test-Path 應回傳 True,兩個 SHA-256 應一致。
3. Hard Link 身分
fsutil hardlink list ".\AGENTS.md"
預期清單同時包含 AGENTS.md 與 CLAUDE.md。內容相同的兩份副本不能當成
Hard Link 證據。
回到 Claude Code 做最後三項驗收
claude --version
- 如果 session 啟動時還沒有頂層
.claude\skills,建立後重啟 Claude Code。 - 輸入
/my-skill,確認 slash autocomplete 能看到該 Skill。 - 用符合 frontmatter
description的自然語言任務,確認 auto-invocation。 - 執行
/context,確認 Memory files 已載入CLAUDE.md。
一般 Read tool 能看到檔案,只能證明檔案可讀。slash autocomplete、
auto-invocation 與 /context 都通過,才能證明原生 discovery 已接上。
執行 Link bootstrap 前,先看它會動哪些檔案
團隊 bootstrap 可能同時處理 metadata、wrapper、專案根目錄標記與清理流程。 如果目的只是讓 Claude Code 看見一個 Skill,手動建立單一 Link 比直接執行整支腳本容易控制。
| 程式行為 | 風險 | 執行前檢查 |
|---|---|---|
| 任何 Reparse Point 都視為已存在 | 未核對正確 target | 檢查 Get-Item ... Target |
實體 .claude\skills 直接跳過 |
雙份 Skill 繼續漂移 | 分類 portable 與 Claude-only Skill |
| 規則檔內容相同就顯示 Hard Link 已存在 | 相同副本被誤認為同一檔案 | 執行 fsutil hardlink list |
| 規則內容不同時改名備份再建立 Link | 目前專案的檔案配置會改變 | review 差異與備份名稱 |
| 清理腳本對一般規則檔直接移除 | 檔案脫離 Hard Link 後仍可能被刪 | 核對 Hard Link set 並另留備份 |
AST parse 只能證明 PowerShell 語法可解析,不能證明檔案變更符合預期。 在隔離的測試專案完成建立與清理流程前,不要把語法檢查當成安全驗收。
卡住時,從這裡查
| 狀況 | 可能原因 | 處理順序 |
|---|---|---|
.claude\skills 已是實體目錄 |
過去人工複製,或內含 Claude-only Skill | 比較差異後採逐 Skill Link |
| Claude 看不到 Skill | 路徑、檔名、description、target 或 session 時機錯誤 | 依序檢查 .claude/skills/<name>/SKILL.md、
Test-Path 與重啟
|
| Symbolic Link 權限不足 | 未開 Developer Mode,shell 也沒有 symlink 權限 | 在 Windows 本機改用 Junction,或調整權限後重試 |
| Hard Link 建立失敗 | AGENTS.md 與 CLAUDE.md 不在同一 volume |
改用 @AGENTS.md import |
修改 CLAUDE.md 後 AGENTS.md 也變了 |
這是 Hard Link 的正常行為 | 需要 Claude-only 內容時改採 import loader |
| 本機可用,Cloud session 看不到 | 外部 Junction 不會隨 clone 出現 | 提交 project Skill、使用 bootstrap 或 plugin |
交付前逐項確認
.agents/skills/<name>/SKILL.md是可攜 Skill 的唯一來源。.claude/skills/<name>的LinkType與Target正確。- Claude path 的
SKILL.md可讀,SHA-256 與來源一致。 /my-skill出現在 slash autocomplete。- 自然語言任務能觸發該 Skill。
/context顯示CLAUDE.md。- 使用 Hard Link 時,
fsutil hardlink list同時列出兩個檔名。 - bootstrap 或團隊文件已記錄 clone 後如何重建 Link。
資料來源與驗證邊界
- Claude Code:Extend Claude with skills
- Claude Code:Manage Claude's memory
- Agent Skills:Adding skills support to your agent
- Microsoft:Hard Links and Junctions
- PowerShell:New-Item
本文只使用以專案根目錄為基準的相對路徑與中性名稱,不記錄作者本機的 使用者名稱、磁碟位置、私人 repository 名稱或實際檔案數量。命令未在讀者環境 執行;實際變更前,請先在可還原的測試專案驗證。