内部专属技能 (Internal Bundled Skills)
Claude Code 的源码中隐藏了一系列特殊的“斜杠命令”,它们被统称为 Bundled Skills。有趣的是,其中最强大的一部分命令被 process.env.USER_TYPE === 'ant' 严密包裹着 —— 它们是 Anthropic 工程师们用来调优、诊断和“调教” Claude 的秘密武器。
它解决了什么问题
它们是硬编码在客户端中的高级宏指令。不同于普通的工具调用,这些技能直接操作会话上下文、读取底层系统指标、甚至能直接向 Slack 频道发送诊断报告。它们展示了 Anthropic 内部是如何进行“吃自家狗粮”(Dogfooding)的。
从源码看实现
这些技能都通过 registerBundledSkill 注册,并根据用户身份决定是否激活:
/stuck:冻结诊断器 (src/skills/bundled/stuck.ts) 这是最硬核的命令。当工程师觉得 Claude 响应变慢时,运行/stuck。它会调用ps命令检查系统中所有 Claude 进程,分析 CPU 占用、RSS 内存,甚至通过进程状态码(如D状态表示 I/O 挂起,T状态表示被 Ctrl+Z 暂停)来定位故障。最神奇的是,它能直接通过 Slack MCP 工具将诊断报告发往内部频道#claude-code-feedback。/skillify:会话转技能 (src/skills/bundled/skillify.ts) 这其实是 Claude Code “技能系统”的元编辑器。它会分析当前会话的session_memory和用户消息,识别出用户完成某项任务的重复性步骤,然后引导用户创建一个新的.SKILL.md文件。它能自动识别哪些步骤需要“人工检查点”(Human checkpoint),哪些步骤可以“派生子代理”(Forked context)执行。/remember:记忆升舱 (src/skills/bundled/remember.ts) Claude 会在会话中自动产生“自动记忆”(Auto-memory)。/remember命令负责将这些零散的记忆进行分类:- 属于项目规范的,建议推广(Promote)到
CLAUDE.md。 - 属于个人偏好的,移动到
CLAUDE.local.md。 - 它还会检测不同层级记忆之间的冲突和重复,保持知识库的整洁。
- 属于项目规范的,建议推广(Promote)到
/lorem-ipsum:压力测试工具 (src/skills/bundled/loremIpsum.ts) 为了测试 Claude 在长上下文下的表现,这个命令可以一键生成多达 50 万个 Token 的填充文本。它内置了一组“单 Token 词表”(ONE_TOKEN_WORDS),确保生成的文本量大的同时,token 计数也极其精准。/verify:变更验证 (src/skills/bundled/verify.ts) 这是一个被保护的实验性技能,用于在模型修改代码后,通过预定义的流程(通常涉及运行应用或测试套件)来自动化验证代码变更的正确性。
限制与陷阱
- Ant 身份隔离:绝大多数此类技能在普通用户的
USER_TYPE下是不可见的。如果你在非 Ant 环境下修改源码强行开启,可能会因为缺少相应的 MCP 工具(如 Slack 发送权限)或特定的文件路径而报错。 - 无模型调用 (disableModelInvocation):像
/debug和/skillify这样的命令通常设置了disableModelInvocation: true。这意味着当你输入这些命令时,Claude 不会先去咨询大模型,而是直接运行本地代码逻辑并返回一段特定的 Prompt。这既节省了 Token,也保证了这些管理指令的确定性。
延伸阅读
- 了解这些技能如何存储在项目里,请阅读
src/skills/bundled/index.ts。 - 看看普通用户也能用的技能是如何实现的,例如
/keybindings或/config。
源码锚点
src/skills/bundled/stuck.ts: 进程监控与 Slack 集成的实现。
📄 src/skills/bundled/stuck.ts — 进程监控与 Slack 集成的实现。
**Only post to Slack if you actually found something stuck.** If every session looks healthy, tell the user that directly — do not post an all-clear to the channel.
If you did find a stuck/slow session, post to **#claude-code-feedback** (channel ID: \`C07VBSHV7EV\`) using the Slack MCP tool. Use ToolSearch to find \`slack_send_message\` if it's not already loaded.
**Use a two-message structure** to keep the channel scannable:
1. **Top-level message** — one short line: hostname, Claude Code version, and a terse symptom (e.g. "session PID 12345 pegged at 100% CPU for 10min" or "git subprocess hung in D state"). No code blocks, no details.
2. **Thread reply** — the full diagnostic dump. Pass the top-level message's \`ts\` as \`thread_ts\`. Include:
- PID, CPU%, RSS, state, uptime, command line, child processes
- Your diagnosis of what's likely wrong
- Relevant debug log tail or \`sample\` output if you captured it
If Slack MCP isn't available, format the report as a message the user can copy-paste into #claude-code-feedback (and let them know to thread the details themselves).
## Notes
- Don't kill or signal any processes — this is diagnostic only.
- If the user gave an argument (e.g., a specific PID or symptom), focus there first.
`
export function registerStuckSkill(): void {
if (process.env.USER_TYPE !== 'ant') {
return
}
registerBundledSkill({
name: 'stuck',
description:
'[ANT-ONLY] Investigate frozen/stuck/slow Claude Code sessions on this machine and post a diagnostic report to #claude-code-feedback.',
userInvocable: true,
async getPromptForCommand(args) {src/skills/bundled/skillify.ts: 从会话历史中提取结构化技能的逻辑。
📄 src/skills/bundled/skillify.ts — 从会话历史中提取结构化技能的逻辑。
function extractUserMessages(messages: Message[]): string[] {
return messages
.filter((m): m is Extract<typeof m, { type: 'user' }> => m.type === 'user')
.map(m => {
const content = m.message.content
if (typeof content === 'string') return content
return content
.filter(
(b): b is Extract<typeof b, { type: 'text' }> => b.type === 'text',
)
.map(b => b.text)
.join('\n')
})
.filter(text => text.trim().length > 0)
}src/skills/bundled/remember.ts: 跨文件记忆管理的 Prompt 模板。
📄 src/skills/bundled/remember.ts — 跨文件记忆管理的 Prompt 模板。
async getPromptForCommand(args) {
let prompt = SKILL_PROMPT
if (args) {
prompt += `\n## Additional context from user\n\n${args}`
}
return [{ type: 'text', text: prompt }]
},src/skills/bundled/loremIpsum.ts: 基于统计概率的高性能填充文本生成器。
📄 src/skills/bundled/loremIpsum.ts — 基于统计概率的高性能填充文本生成器。
const ONE_TOKEN_WORDS = [
// Articles & pronouns
'the',
'a',
'an',
'I',
'you',
'he',
'she',
'it',
'we',
'they',
'me',
'him',
'her',
'us',
'them',
'my',
'your',
'his',
'its',
'our',
'this',
'that',
'what',
'who',
// Common verbs
'is',
'are',
'was',src/skills/bundled/debug.ts: 差异化的/debug命令实现(对 Ant 提供日志预览,对普通用户提供引导)。
📄 src/skills/bundled/debug.ts — 差异化的 `/debug` 命令实现(对 Ant 提供日志预览,对普通用户提供引导)。
const DEFAULT_DEBUG_LINES_READ = 20
const TAIL_READ_BYTES = 64 * 1024
export function registerDebugSkill(): void {
registerBundledSkill({
name: 'debug',
description:
process.env.USER_TYPE === 'ant'
? 'Debug your current Claude Code session by reading the session debug log. Includes all event logging'
: 'Enable debug logging for this session and help diagnose issues',
allowedTools: ['Read', 'Grep', 'Glob'],
argumentHint: '[issue description]',
// disableModelInvocation so that the user has to explicitly request it in
// interactive mode and so the description does not take up context.
disableModelInvocation: true,
userInvocable: true,
async getPromptForCommand(args) {
// Non-ants don't write debug logs by default — turn logging on now so
// subsequent activity in this session is captured.
const wasAlreadyLogging = enableDebugLogging()
const debugLogPath = getDebugLogPath()
let logInfo: string
try {
// Tail the log without reading the whole thing - debug logs grow
// unbounded in long sessions and reading them in full spikes RSS.
const stats = await stat(debugLogPath)
const readSize = Math.min(stats.size, TAIL_READ_BYTES)
const startOffset = stats.size - readSize
const fd = await open(debugLogPath, 'r')