Rulestack

您輸入 /fix-issue 123 後,Claude Code 會將其擴展為包含團隊標準的完整提示。自訂斜線指令是 Claude Code 中成本最低的自動化方式——只需一個 Markdown 檔案,零配置——但它們已發生變化,這種變化很容易被忽略:自訂指令已合併到技能中。您的 .claude/commands/ 檔案仍然有效,但合併後的模型解釋了幾個看起來像錯誤的現象(參數未展開、工具授權在任務進行中消失),並新增了指令從未具備的功能。

以下是根據 2026 年 7 月下旬官方文件驗證的目前行為。

單一檔案版本仍然有效

將 Markdown 檔案放入您的專案中:

<!-- .claude/commands/fix-issue.md -->
---
description: "Fix a GitHub issue by number"
---
Fix GitHub issue $ARGUMENTS following our coding standards.
Read the issue with `gh issue view`, locate the relevant code,
implement the fix, and add a regression test.

Enter fullscreen mode Exit fullscreen mode

輸入 /fix-issue 123 會傳送該內容,並將 $ARGUMENTS 替換為 123

合併意味著此檔案和位於 .claude/skills/fix-issue/SKILL.md 的技能都會建立 /fix-issue 且行為相同。技能額外提供的功能包括:

  • 一個用於支援檔案的目錄(範本、指令碼、參考文件,Claude 只會在需要時載入)
  • 前置資料,用於控制可以呼叫它——您、Claude 或兩者
  • 自動呼叫:當您的對話符合其描述時,Claude 可以載入它

如果指令和技能共用名稱,技能優先。我的實務規則是:一次性的個人捷徑可以留在 commands/;任何您想要發展或分享的內容都應該放在 skills/ 中。(如何撰寫實際會觸發的描述是另一個主題——我在 SKILL.md 指南 中有說明。)

參數:$ARGUMENTS$0 以及引號規則

三條展開規則涵蓋了我看到的大多數困惑:

1. $ARGUMENTS 是輸入的完整字串。 /fix-issue 123 high-priority$ARGUMENTS 變成 123 high-priority

2. 索引存取為零基且經過 shell 引號處理。 $ARGUMENTS[0](或簡寫 $0)是第一個參數。引號會將單詞分組:

/migrate-component "search bar" React Vue
→ $0 = search bar, $1 = React, $2 = Vue

Enter fullscreen mode Exit fullscreen mode

3. 缺少的值根據佔位符類型有不同的行為。 沒有對應參數的索引佔位符(當您只傳遞一個參數時的 $2)會在文字中保持不變。在 frontmatter 中宣告的命名佔位符會展開為空字串。如果您需要在文字中放置文字的美元數字($1.00),請使用逸出: \$1.00

另一個安全機制:如果您傳遞參數但檔案中完全沒有 $ARGUMENTS,Claude Code 會在結尾附加 ARGUMENTS: <your input>,因此您的輸入不會被靜默丟棄。

即時資料注入:!`command`

這是將預先準備的提示轉變為有根據提示的功能。像這樣的行:

## Current diff
!`git diff HEAD`

Enter fullscreen mode Exit fullscreen mode

會在 Claude 看到任何內容之前執行 shell 指令,並將輸出替換佔位符。Claude 接收的是實際的 diff,而不是去抓取它的指令——減少一次工具往返,也沒有模型「總結」它從未讀取的 diff 的風險。

替換是單次通過:指令的輸出無法發出另一個 !`…` 佔位符進行第二次展開。請將其視為資料,而不是巨集。

allowed-tools 是一次性授權,而非工作階段設定

這是合併模型中最常見的意外。像這樣的前置資料:

allowed-tools: Bash(git add:*), Bash(git commit:*)

Enter fullscreen mode Exit fullscreen mode

會預先核准這些工具僅用於呼叫該技能的該次回合。當您傳送下一則訊息時,授權就會清除——即使技能的內容仍然在上下文中。因此,「為什麼 Claude 再次要求相同指令的權限?」通常是這個原因:指令持續存在,但授權沒有。重新呼叫技能會重新套用它。

兩個相關說明:

  • allowed-tools 不會限制任何內容。未列出的工具仍然可以在您正常的權限設定下使用。
  • ${CLAUDE_SKILL_DIR} 會在主體和 allowed-tools 中展開,因此技能可以附帶指令碼並精確預先核准該指令碼的呼叫——無需提示,無需萬用字元。

如果您想要一個在整個工作階段中持續存在的授權,那應該放在您的權限規則中——allow/deny/ask 比對邏輯是另一個雷區

決定誰可以呼叫它

預設情況下,您和 Claude 都可以執行任何技能。兩個前置資料開關可以改變這一點:

  • disable-model-invocation: true —— 只有您可以觸發它。用於具有副作用且時機重要的任何操作:/deploy/commit/send-release-notes。您不希望模型因為程式碼「看起來準備好了」就進行部署。
  • user-invocable: false —— 只有 Claude 可以載入它。用於不是有意義操作的背景知識,例如 legacy-system-context 技能。

技能的描述總是位於上下文中,因此 Claude 知道有哪些技能存在;主體在呼叫時載入。

主體會持續存在——請像撰寫常規命令一樣撰寫

一旦被呼叫,渲染後的內容會在對話的剩餘工作階段中持續存在(重新呼叫相同的技能會新增簡短的「已載入」提示,而不是重複)。兩個後果:

  1. 每一行都是重複的 token 成本。說明要做什麼;跳過關於為什麼的冗長說明。
  2. 將指令撰寫為常規規則(「編輯 Y 後總是執行 X」),而不是一次性步驟——Claude 不會在後續回合重新讀取檔案。

在上下文壓縮後,最近的技能會在固定的 token 預算內重新附加,因此長時間的工作階段可能會靜默丟棄較舊的技能——詳情請見 什麼會在壓縮後保留

什麼時候斜線指令不是正確的工具

  • Claude 應該始終知道的事實 → CLAUDE.md 中的一行。
  • 您一直貼上的程序 → 一個技能。這是最佳選擇。
  • 必須每次都確定性地發生的事情 → 一個 hook。技能依賴模型選擇是否遵守;hooks 不會詢問。
  • 太大而無法放入上下文的參考資料 → 帶有支援檔案的技能,從 SKILL.md 引用並按需載入。

快速陷阱檢查清單

  • $0第一個參數(零基),引號會將單詞分組
  • 未比對的 $N 保持原文;未比對的命名參數變為空字串
  • !`command` 在 Claude 讀取任何內容之前執行;單次通過
  • allowed-tools 在您的下一則訊息時清除
  • 與內建技能同名的專案技能(code-review)會取代
  • .claude/commands/ 仍然有效;技能是建議的途徑

我維護 Rulestack —— 為 Claude Code、Cursor 和 Codex 提供的版本化規則與技能包,與此類變更保持同步:https://rulestack.gumroad.com?ref=devto

關於 AI 編碼工作流程的每日筆記請見 Bluesky:https://bsky.app/profile/ai-shop.bsky.social