將該程序移至 Claude Code 技能中:一個 SKILL.md 檔案、一個綁定的腳本,以及一個僅在需要撰寫說明時才載入的樣式參考。以下是每個部分所需的成本,以及何時載入。Anthropic 的 Agent Skills 概述將技能分為三個層級,每個層級在不同時間載入:
| 層級 | 載入時機 | 文件中的成本說明 |
| :------------- | :------------- | :--------------------- |
| 名稱 + 描述 | 始終,啟動時 | 每個技能約 100 個 token |
| SKILL.md 主體 | 技能觸發時 | 低於 5k 個 token |
| 綁定檔案和腳本 | 讀取或執行時 | 存取前無成本 |
腳本還有額外折扣。當 Claude 執行綁定腳本時,只有其輸出會進入上下文,而不是程式碼本身。因此,確定性的工作(列出提交、分組)屬於腳本,而判斷(使用者關心的提交)則屬於 Markdown。
在將所有內容從 CLAUDE.md 移出之前,有一個注意事項。一旦技能被調用,其內容將在會話的其餘時間內保留在對話中,並且 Claude Code 在後續回合中不會重新讀取該檔案。因此,節省的成本僅限於那些從未觸及發布的會話。在發布會話本身中,技能一旦觸發,其主體就會一直保留在上下文中。
只有索引卡始終放在桌上。資料夾和抽屜只有在任務需要時才會打開。現在,讓我們建立釋出說明技能。專案技能位於 .claude/skills/<name>/SKILL.md,個人技能則位於 ~/.claude/skills/<name>/SKILL.md(技能文件)。使用專案位置,以便技能隨儲存庫一起發布:
```
.claude/skills/release-notes/
├,SKILL.md
├,reference/
│ └,style.md
└,scripts/
└,commits.sh
```
從腳本開始。它會找到最後一個標籤(或將其作為參數),列出自該標籤以來的所有非合併提交,並用其 Conventional Commits 類型標記每一行,這樣模型就不必解析前綴了:
```bash
#!/usr/bin/env bash
Usage: commits.sh [from-tag]
Prints "<type>\t<hash> <subject>" for each commit
since the tag, grouped by type.
set -euo pipefail
from="${1:-}"
if [ -z "$from" ] ; then
from="$(git describe --tags --abbrev=0 2>/dev/null \
|| true)"
fi
if [ -n "$from" ] ; then
echo "# commits since $from"
range="$from..HEAD"
else
echo "# no tag found, listing all commits"
range="HEAD"
fi
git log "$range" --no-merges --pretty='format:%h %s' | awk '
{ type = "other" }
$2 ~ /^feat(\([^\)]*\))?!?:/ { type = "feat" }
$2 ~ /^fix(\([^\)]*\))?!?:/ { type = "fix" }
{ print type "\t" $0 }
' | sort -s -k1,1
```
git describe --tags --abbrev=0 只會印出從 HEAD 可達到的最近標籤,包括輕量級標籤。|| true 則防止在尚未有標籤的儲存庫中,set -e 終止腳本。
現在是樣式參考。這就是以前在 CLAUDE.md 中的四十行內容,現在精簡為模型無法猜測的部分:
```markdown
Release notes style
Headings
Use these, in this order, and skip empty ones:
Features, ### Fixes, ### Other
Bullets
- Start with a past-tense verb: "Added", "Fixed".
- Describe the effect for the user, not the code.
- End with the short hash in parentheses: (a1b2c3d).
- A ! right before the colon marks a breaking change. List it first under its heading, prefixed Breaking: .
Leave out
- Refactors with no visible effect.
- Dependency bumps, unless they fix a security issue.
```
接著是 SKILL.md,它將兩者結合起來:
```yaml
---
name: release-notes
description: >-
Drafts user-facing release notes from the git commits since the last tag,
grouped into Features, Fixes and Other. Use when the user asks for release
notes, a changelog entry, what shipped since a version, or a summary of
changes for a release. Not for single commit messages or PR descriptions.
---
Release notes
1. Get the commits by running: bash "${CLAUDE_SKILL_DIR}/scripts/commits.sh" [tag]
Pass a tag only if the user named one.
2. Read reference/style.md before writing anything.
3. One bullet per user-visible change. Merge commits that describe the same change. Drop chore, ci, test and docs commits unless the user asks for them.
4. Reply with Markdown only. Edit CHANGELOG.md only if the user asks you to.
```
>- 是純 YAML 語法:它將縮排的行摺疊成一個字串,這樣長描述保持可讀性,並且其中一個冒號也不會破壞解析。${CLAUDE_SKILL_DIR} 是 Claude Code 會用技能本身的目錄填入的替換變數,因此腳本路徑可以在任何工作目錄中運作。
名稱必須是小寫字母、數字和連字號,並且在 Anthropic 的其他介面上不能包含「anthropic」或「claude」。參考檔案直接從 SKILL.md 連結,深度為一層,因為最佳實踐指南警告說,Claude 可能只會部分讀取透過參考鏈接到的檔案。
你也可以使用技能文件的內聯 shell 語法(一個驚嘆號後跟一個反引號指令)內聯腳本,它會在 Claude 看到技能之前執行並將輸出貼上。文件指出,失敗的指令會中止整個調用,而且這裡的標籤參數是可選的,因此讓 Claude 執行腳本是更簡單的選擇。
Claude Code 會監控技能目錄,並在會話中途載入新的或編輯過的技能。如果會話開始時 .claude/skills/ 不存在,Claude Code 尚未監控它:執行 /reload-skills 來載入技能,並在該會話中每次編輯後再次執行,或者開始一個新會話。
測試它是否觸發,以及它是否保持靜默。在至少有一個標籤的儲存庫中啟動一個新會話。首先詢問 What skills are available?,這是疑難排解指南中的一個檢查。release-notes 應該在列表中。如果它出現但從未觸發,請檢查 YAML:當 frontmatter 解析失敗時,技能仍然會載入空元資料,因此 /release-notes 可以運作,但 Claude 沒有描述可以匹配。
執行 claude --debug 以查看解析錯誤。一個簡單的錯誤原因:未引號的單行描述包含一個冒號後跟一個空格。
然後在界線的兩側執行提示詞:
| 提示詞 | 技能是否應載入? |
| :--------------------------------------- | :--------------- |
| Write release notes for everything since v1.4.0 | 是 |
| What shipped since the last tag? | 是 |
| Draft a CHANGELOG entry for this release | 是 |
| Write a commit message for my staged changes | 否 |
| Explain what git describe does | 否 |
「否」的那些行很有用。它們與技能共享詞彙(commits, git, tags),但仍應在沒有技能的情況下處理。如果提交訊息提示詞引入了技能,則說明過於寬泛。要查看技能的變化,請獲取基準線。在 .claude/settings.local.json 中使用 skillOverrides 將其關閉,在新會話中執行相同的提示詞,然後移除覆寫:
```json
{
"skillOverrides": {
"release-notes": "off"
}
}
```
關於成本,/context 中的「Skills」行會報告應用預算後技能列表的大小,因此它與模型接收到的內容相符,而 /skill-doctor(Claude Code v2.1.252 或更高版本)則會報告每個技能的上下文成本和調用次數。手動執行五個提示詞可以捕捉明顯的遺漏。
要測試超過五個,文件中的 skill-creator 插件會生成「應該觸發」和「不應該觸發」的提示詞,測量命中率並建議描述編輯。使用 /plugin install skill-creator@claude-plugins-official 安裝它。
描述是唯一在「門口」被檢查的東西。主體從不參與是否載入的投票。描述才是真正的提示詞。SKILL.md 中 frontmatter 以下的所有內容在技能被選中之前都是不可見的。選擇僅根據描述進行,Anthropic 的概述稱 Claude 會「將你的請求與之匹配」。一個模糊描述背後再好的主體也永遠不會運行。
說明「做什麼」和「何時做」。最佳實踐指南要求兩者兼顧:「幫助發布」兩者都失敗了。「從上次標籤以來的 Git 提交中草擬面向使用者的釋出說明。當使用者要求釋出說明、變更日誌條目、自某版本以來發布的內容或發布變更摘要時使用。」這為模型提供了一個任務和一組要匹配的短語。
以第三人稱撰寫。描述被注入到系統提示詞中,指南警告說「我可以幫助你」或「你可以使用這個」可能會導致發現問題。「草擬釋出說明」從任何角度讀起來都是正確的。使用你的使用者會輸入的詞語。沒有人會要求「發布工件摘要」。他們會問「自 1.4 版以來發布了什麼」或「撰寫變更日誌」。將這些短語放進去。文件對於技能未觸發的第一個疑難排解步驟是檢查描述是否「包含使用者會自然說出的關鍵字」。
將關鍵用例放在首位。在 Claude Code 中,組合的描述和 when_to_use 文字預設在列表中被截斷為 1,536 個字元。超出此範圍的任何內容都永遠不會到達模型,因此請將重要的句子放在前面。整個列表也有一個預算,預設為模型上下文視窗的 1%。
如果你有很多技能並且列表溢出,Claude Code 會捨棄整個描述,從你調用最少的技能開始。一個新技能從零調用開始,因此它是一個早期候選者。檢查 /context 中的「Skills」行,並在 skillOverrides 中將低優先級技能設定為「name-only」以釋放空間。
命名邊界。「不適用於單個提交訊息或 PR 描述」這行是本教學的設計選擇,而不是文件中的規則。當附近請求不斷觸發技能時,它就有了存在的價值。文件記載的過度觸發修復方法是使描述更具體,而明確的排除就是其中一種方法。
保持在可攜式限制內。在 Claude API 和 claude.ai 上,描述必須非空,最多 1,024 個字元,並且沒有 XML 標籤。Claude Code 自己的文件只提到 1,536 個字元的列表截斷,但保持在 1,024 字元以下可以使技能在這些介面上可攜。
當技能是錯誤的工具時。如果你只希望在要求時才獲得釋出說明,請在 frontmatter 中添加 disable-model-invocation: true。這樣描述就會完全離開上下文,技能只會在你輸入 /release-notes 時運行。
這是最便宜的選項,也是任何你希望手動觸發的副作用的正確選擇。如果一個規則必須每次都成立,例如「在不運行測試的情況下絕不推送標籤」,那麼技能就是錯誤的歸宿。文件建議為此使用 hook,因為 hook 會在其事件發生時運行,無論 Claude 是否遵循任何技能。
CLAUDE.md 仍然是每個會話都需要的事實的存放地:建置指令、佈局、慣例。其他一切都可以保留在磁碟上,直到請求需要它。如果這篇文章對你有用。技能描述是一個只有一個任務的提示詞,那就是為正確的請求被選中,而這正是《提示工程袖珍指南》所花時間探討的提示詞類型:具體化、選擇模型會匹配的詞語,以及測試未命中和命中。如果你正在修剪一個已經變成手冊的 CLAUDE.md,同樣的習慣也適用。