Windows 實作筆記 · 相對路徑示例

讓 Claude Code 讀到 .agents/skills

Claude Code 的專案 Skill 入口是 .claude/skills;portable Skills 若只放在 .agents/skills,原生 discovery 不會接上。本文先確認 target 是否已有內容,再選整棵 Junction 或逐 Skill Link。共用規則由 CLAUDE.md 匯入 @AGENTS.md,最後回到 Claude Code 驗收 slash autocomplete、auto-invocation 與 /context。

環境:Windows / PowerShell 預設:逐 Skill Link 驗收:slash / auto / context

短答案

先讀取 .claude/skills 的 LinkType 與 Target。目錄已有 Claude-only 內容時,保留實體目錄,只替 portable 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 補充

.claude/skills 尚不存在、而且所有 Skills 都能共用時,整棵 Junction 才是 合理選項。規則檔優先使用 @AGENTS.md;Hard Link 只留給固定在 Windows/NTFS、同一 volume,且兩個檔名必須永遠同內容的環境。

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,不只看檔案存在。

既有實體目錄現在會被擋下

vibeLinker 把 .agents\skills 定為唯一 Skill root,再為 Claude 與 Gemini 建立 Junction。舊版遇到實體目錄時只會跳過;目前版本會核對 Link 的實際 target, 把實體副本或錯誤 target 記成契約違規,最後以 exit code 1 結束。

PowerShell · mapping 示意
$directoryLinks = [ordered]@{
    ".claude\skills" = ".agents\skills"
    ".gemini\skills" = ".agents\skills"
}

$instructionLinks = [ordered]@{
    "AGENTS.md" = "AGENTS.md"
    "CLAUDE.md" = "AGENTS.md"
    "GEMINI.md" = "AGENTS.md"
}

2026-08-29 重驗結果

  • .agents\skills 是實體 canonical 目錄。
  • .claude\skills 是 Junction,target 正確指向 .agents\skills。
  • setup_links.ps1 與 remove_links.ps1 的 AST 語法錯誤數皆為 0。
  • 本次沒有執行 setup/remove,也沒有建立受檢 repo 缺少的 .gemini\skills。
  1. bootstrap 解析 canonical Skill root 與 host 端 target。
  2. 既有 Junction 會比對實際 target;相符才視為已接好。
  3. 實體副本或錯誤 target 會留下違規紀錄並讓 setup 失敗。

舊失敗模式仍值得保留:發現實體 .claude\skills 時,先分類 portable 與 Claude-only Skill,完成差異與備份後才遷移。直接刪除可能把 Claude-only Skill 一併移除。

動手前,先確認 .claude\skills 是什麼

  • 以下命令都在專案根目錄執行。
  • .agents\skills 必須存在,每個 Skill 目錄內要有 SKILL.md。
  • 查清楚 .claude\skills 是實體目錄、Junction,還是 Symbolic Link,並核對 target。
  • Hard Link 的來源與目標必須位於同一個 volume。
  • Junction 可跨本機 volume,但不能指向映射的網路磁碟。
PowerShell · 唯讀盤點
$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
}
這一步做什麼只讀取兩個目錄的型態與 target。
可以繼續來源存在;既有 Link 顯示 ReparsePoint,而且 Target 正確。
先停下來.claude\skills 是實體目錄或指到錯誤 target,先比較內容。

兩種接法怎麼選

整個目錄做 Junction

適合所有 Skill 都能共用,而且 .claude\skills 尚不存在的專案。

  • 結構簡單。
  • 無法保留 Claude-only Skill。
  • 建立後仍要到 Claude Code 裡驗收。
現況 建議
兩邊 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。

PowerShell · 整個目錄的 Junction
$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。

規則檔不必再複製一份

Hard Link

只適合固定 Windows/NTFS、同一 volume,而且兩個檔名永遠必須同內容的環境。

方案 A:薄 CLAUDE.md import

CLAUDE.md
@AGENTS.md

## Claude Code

- 把只適用 Claude Code 的補充規則放在這裡。

方案 B:以 Hard Link 共用規則檔

PowerShell · AGENTS.md and CLAUDE.md 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

PowerShell · 檢查 Junction / Symbolic Link
Get-Item -LiteralPath ".claude\skills\my-skill" -Force |
    Select-Object FullName, Attributes, LinkType, Target

預期 Attributes 包含 ReparsePoint,LinkType 為 Junction 或 SymbolicLink,且 Target 指向預期來源。

2. Entrypoint 與 SHA-256

PowerShell · 檢查 SKILL.md 與內容 hash
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 身分

Windows · 列出 Hard Link set
fsutil hardlink list ".\AGENTS.md"

預期清單同時包含 AGENTS.md 與 CLAUDE.md。內容相同的兩份副本不能當成 Hard Link 證據。

回到 Claude Code 做最後三項驗收

PowerShell · 記錄 Claude Code 版本
claude --version
  1. 如果 session 啟動時還沒有頂層 .claude\skills,建立後重啟 Claude Code。
  2. 輸入 /my-skill,確認 slash autocomplete 能看到該 Skill。
  3. 用符合 frontmatter description 的自然語言任務,確認 auto-invocation。
  4. 執行 /context,確認 Memory files 已載入 CLAUDE.md。

一般 Read tool 能看到檔案,只能證明檔案可讀。slash autocomplete、 auto-invocation 與 /context 都通過,才能證明原生 discovery 已接上。

Link bootstrap 會碰哪些檔案

整套 bootstrap 會處理 metadata、wrapper、專案根目錄標記與清理流程。只想讓 Claude Code 看見一個 portable Skill 時,手動建立單一 Link 的變更面較小。

程式行為 風險 執行前檢查
Junction 已存在 Link 可能指到錯誤來源 檢查 Get-Item ... Target;目前腳本也會解析實際 target
.claude\skills 是實體目錄或錯誤 Link setup 記錄契約違規並回傳 exit code 1 分類 portable 與 Claude-only Skill,備份後再修復
規則檔內容相同就顯示 Hard Link 已存在 相同副本被誤認為同一檔案 執行 fsutil hardlink list 或 scripts/validate_host_contract.py
規則內容不同時改名備份再建立 Link 目前專案的檔案配置會改變 review 差異與備份名稱
remove_links.ps1 拆除 Junction 目標辨識錯誤會讓清理範圍失真 核對 LinkType 與 target;腳本以非遞迴刪除移除 Link 本身

AST parse 只能證明 PowerShell 語法可解析,不能證明檔案變更符合預期。 在隔離的測試專案完成建立與清理流程前,不要把語法檢查當成安全驗收。

卡住時,從這裡查

狀況 可能原因 處理順序
.claude\skills 已是實體目錄 過去人工複製,或內含 Claude-only Skill 先比較並備份;vibeLinker setup 會回傳契約違規,不會自動覆蓋
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。

資料來源與驗證邊界

2026-08-29 已重查 Claude Code 官方文件、vibeLinker 控制流程與本機 Link 狀態;本機 Claude Code 版本為 2.1.247。這次沒有執行 setup/remove,也沒有替讀者環境 建立任何 Link。實際變更前,請先在可還原的測試專案驗證。