Claude Code Skills 全景指南:从概念解析到高级工作流构建

解锁 AI 编程潜能 | 深入理解 Skills 机制、编写规范与生态复用

本文深度解析 Claude Code 的核心概念——Skills。超越基础安装,探讨 Skills 究竟是代码库还是提示词模板?详解其 YAML/Markdown 结构设计、自定义编写技巧、参数传递机制及社区优秀 Skills 的调用方法。助您从‘只会提问’进阶为‘构建自动化 AI 工作流’的专家
摘要
安装了 Claude Code 只是第一步,真正掌握其精髓在于理解并运用’Skills’。很多用户困惑:Skills 到底是程序代码还是简单的 Markdown 文档?如何编写属于自己的高效 Skill?如何复用社区大神的成果?本文将抽丝剥茧,从底层逻辑到实战编写,带您彻底攻克 Skills 这一核心概念,让 Claude Code 从‘聊天机器人’进化为您的‘专属超级工程师’

1. SKILLs是什么

要想真正入门Claude Code,绕不过的一个概念就是SKILLs,一直困惑在skills到底是什么?算什么?程序还是简单的md文档?该怎么写?别人写的skills怎么用?所以准备从不同的角度和文章来深入理解skill到底是什么?只有深入才能浅出,而不是简单的安装和调用。

1.1 函数是什么?

函数,从数学开始大家就开始接触了,最开始的定义就是

数学函数:在一个变化的过程中,有两个变量x和y,对于每一个x,都有唯一确定的一个y,y就是x的函数。重点时函数不是式子本身,而是从x到y的对应规则

而在编程中,函数是什么?他们不是两套东西,而是同一思想在不同世界的表达

函数= 一个可以反复使用的操作说明书

编程中的函数时一段被命名的代码,用来完成一个特定任务,常见的形式

参数 ──► [代码逻辑] ──► 返回值
                └──► 其他行为(打印 / 文件 / 网络)

就像最简单的编程函数

def add(x):
    return 2*x + 1

不就等价于$ y=2*x+1 $。

你告诉它要做什么(输入),帮你计算出来结果(输出)。就像磨咖啡一样,你给咖啡机豆子和水,它磨出来咖啡,咖啡机就是函数整体,能够帮你重复的完成磨咖啡的动作。

function

whats function

1.2 函数调用

函数调用(function calling), 不是新发明的函数,而是让AI大模型知道什么时候,如何去调用外部程序的一套机制。

🧠 让 AI 从“只会说话”,进化成“会做事”

早期AI,GPT3的时候只能输出文本,不能调用数据库,调用API,执行代码,控制系统。2023年OpenAI引入Function Calling,不是让模型直接调用函数,而是让模型结构化告诉你:它想调用哪个函数,用什么参数。

核心设计

生成json便签文件

{
  "name": "get_weather",
  "arguments": {
    "city": "Shanghai",
    "date": "today"
  }
}

现在的共识是:函数调用不是“功能”,而是 AI 与现实世界的“接口层(Interface Layer)”

举个生活的例子:AI点外卖

1. 现实世界AI不知道的事:你的位置,附近的点,几点,什么店,什么菜,都是真实世界里的,不是模型中的
2. 提前给AI准备好生活的函数:`get_location()`,`get_nearby_restaurants(location)`
3. AI进行判断,需要什么工具
4. AI第一次函数调用,AI输出json文件,程序得到json输入文件后执行输出json文件
5. AI和你确人,附近是不是附近有「老王汉堡」,招牌牛肉堡 28 元,要不要点这个?
6. 你回复后,AI调用下单的函数

AI 中的函数调用,本质上就是: AI 做决策 (AI理解意图) → 选择一个“可用操作” → 把参数告诉程序 → 执行 → 得到结果 → 继续推理

AI 的函数调用瓶颈 = “从模型的决策到函数执行,再到反馈回模型的过程中可能出错、延迟或受限的地方”

AI 可能会“想要做事”,但函数调用链上有多个环节容易卡住或出错。

1.3 Skill诞生

Skill本质上应该是由一个或多个函数组合而成的能力,带逻辑、决策和上下文

skill可以理解成员工手册(怎么调用函数,什么时候调用函数)+工具箱(函数)

  • 手册就是相当于给你一个说明书,告诉你怎么调用函数,什么时候调用函数;就像你告诉新来的员工什么时候做什么,怎么做;不同的物品着火了用什么干粉还是二氧化碳灭火器?

Claude Code遵循agent skills规则

(Agent skills)代理技能是包含指令、脚本和资源的文件夹,代理可以发现并使用它们来更准确、更高效地完成任务。

agent skills

agent skills

直观的来看,Skills就是一个文件夹,可以放在用户.claude中,也可以放在项目下/project/.claude

    1. SKILL.md文件,用自然语言写的,告诉大模型这个SKill是干什么的,什么情况下用,怎么用,什么注意事项等
    1. 脚本。在SKILL.md中,会调用一些脚本,脚本就是函数,经常放在skill目录下的src目录中
    1. 资源。在SKILL.md中,会调用一些资源,资源就是数据,经常放在skill目录下的data目录中

还有个重要的机制–渐进式披露

渐进式披露 = 不一次性把所有 skills 给模型,而是按“需要 → 能力 → 风险”逐步解锁。

注记

Skills就像是装了锤子,斧子,螺丝刀和说明书的工具箱,说明书告诉你每个工具该怎么用,什么时候用。各个工具就是可以调用的函数,用来完成某些任务的脚本。

2.Skills 底层

Claude 的 Agent Skills 系统代表了一种复杂的基于提示词的元工具架构,通过专门的指令注入来扩展 LLM 的能力。与传统的函数调用或代码执行不同,skills 通过 提示词扩展和上下文修改 来改变Claude 处理后续请求的方式,而无需编写可执行代码

Claude Code你可以把ReadWrite等当成工具,Cluade Code代理工具一般能够调用计算机的读写git等,而Skills也作为一种元工具,可以调用其他工具,比如/explain-code/code-review/code-generate等,这些工具就是Skills

Skills 被定义为包含指令、脚本和资源的文件夹,Claude 可以在需要时加载。Claude 使用 声明式、基于提示词的系统 来进行 skill 发现和调用。AI 模型(Claude)根据其系统提示词中呈现的文本描述来决定调用 skills。在代码层面没有算法化的 skill 选择或 AI 驱动的意图检测。 决策完全发生在 Claude 的推理过程中,基于提供的 skill 描述。

Skills 不是可执行代码。它们 不会 运行 Python 或 JavaScript,背后也没有 HTTP 服务器或函数调用。它们也不是硬编码到 Claude 的系统提示词中。Skills 存在于 API 请求结构的独立部分。

Skills 是专门的提示词模板,将特定领域的指令注入到对话上下文中。当一个 skill 被调用时,它会修改对话上下文(通过注入指令提示词)和执行上下文(通过更改工具权限并可能切换模型)。skill 不是直接执行操作,而是扩展为详细的提示词,为 Claude 解决特定类型的问题做准备。每个 skill 都作为 Claude 看到的工具模式的动态添加出现。

Skill 工具(大写 S)= 管理所有 skills 的元工具。它与 Read、Write、Bash 等一起出现在 Claude 的 tools 数组中。

skills(小写 s)= 单个 skills,如 pdf、skill-creator、internal-comms。这些是 Skill 工具加载的专门指令模板。

Claude如何使用skills

Claude如何使用skills

skill 选择机制在代码层面没有算法路由或意图分类。Claude Code 不使用嵌入、分类器或模式匹配来决定调用哪个 skill。相反,系统将所有可用的 skills 格式化为嵌入在 Skill 工具提示词中的文本描述,并让 Claude 的语言模型做出决定。这是纯粹的 LLM 推理。没有正则表达式,没有关键字匹配,没有基于 ML 的意图检测。决策发生在 Claude 通过 transformer 的前向传递中,而不是在应用程序代码中。

Skills是Claude 做准备来解决问题的,而不是直接解决问题

2.1 编写SKILL.md

SKILL.md 是 skill 提示词的核心。它是一个遵循两部分结构的 markdown 文件——frontmatter 和内容。frontmatter 配置 skill 如何运行(权限、模型、元数据),而 markdown 内容告诉 Claude 做什么。Frontmatter 是用 YAML 编写的 markdown 文件头部。

技能通过 SKILL.md 顶部的 YAML 前置元数据和随后的 markdown 内容进行配置。

┌─────────────────────────────────────┐
│ 1. YAML Frontmatter (Metadata)      │ ← 配置
│    ---                              │
│    name: skill-name                 │
│    description: Brief overview      │
│    allowed-tools: "Bash, Read"      │
│    version: 1.0.0                   │
│    ---                              │
├─────────────────────────────────────┤
│ 2. Markdown Content (Instructions)  │ ← Claude 的提示词
│                                     │
│    Purpose explanation              │
│    Detailed instructions            │
│    Examples and guidelines          │
│    Step-by-step procedures          │
└─────────────────────────────────────┘

参考内容添加 Claude 应用于你当前工作的知识。约定、模式、风格指南、领域知识。此内容内联运行,以便 Claude 可以将其与你的对话上下文一起使用。

任务内容为 Claude 提供特定操作的分步说明,如部署、提交或代码生成。这些通常是你想使用 /skill-name 直接调用的操作,而不是让 Claude 决定何时运行它们。添加 disable-model-invocation: true 以防止 Claude 自动触发它。

2.2 SKILL.md 元数据

frontmatter 包含控制 Claude 如何发现和使用 skill 的元数据。

字段 是否必须 实际作用 不写的后果
name Skill 的显示名 用目录名代替
description ❌(但强烈推荐) Claude 判断“什么时候用你” Claude 很可能永远不会自动用
argument-hint /skill 自动补全提示 手动调用体验差
disable-model-invocation 禁止自动触发 Claude 可能会“多管闲事”
user-invocable 是否出现在 / 菜单 默认可见
allowed-tools 工具白名单 Claude 可能频繁请求授权
model 指定模型 使用默认模型
context 是否 fork 子上下文 默认共享上下文
agent 子代理类型 只有 fork 时才需要
hooks 生命周期钩子 不启用自动化行为

2.3 增加支持文件

技能可以在其目录中包含多个文件,这使 SKILL.md 专注于要点,同时让 Claude 仅在需要时访问详细的参考材料。大型参考文档、API 规范或示例集合不需要在每次技能运行时加载到上下文中。

my-skill/
├── SKILL.md (required - overview and navigation)
├── reference.md (detailed API docs - loaded when needed)
├── examples.md (usage examples - loaded when needed)
└── scripts/
    └── helper.py (utility script - executed, not loaded)

然后从SKILL.md中引用支持文件,以便 Claude 知道每个文件包含什么以及何时加载它:

## Additional resources

- For complete API details, see [reference.md](reference.md)
- For usage examples, see [examples.md](examples.md)

2.4 限制工具访问

  • 使用 allowed-tools 字段来限制技能处于活动状态时 Claude 可以使用哪些工具。此技能创建一个只读模式,其中 Claude 可以浏览文件但不能修改它们:

  • !`command “ 语法在技能内容发送给 Claude 之前运行 shell 命令。命令输出替换占位符,所以 Claude 接收实际数据,而不是命令本身。

  • 你和 Claude 都可以在调用技能时传递参数。参数可通过 $ARGUMENTS 占位符获得。

---
name: fix-issue
description: Fix a GitHub issue
disable-model-invocation: true
---

Fix GitHub issue $ARGUMENTS following our coding standards.

1. Read the issue description
2. Understand the requirements
3. Implement the fix
4. Write tests
5. Create a commit

当你运行 /fix-issue 123 时,Claude 收到”按照我们的编码标准修复 GitHub 问题 123…”

3. SKILLs实践

重要

关键见解: Skill = 提示词模板 + 对话上下文注入 + 执行上下文修改 + 可选的数据文件和 Python 脚本

3.1 入门–创建你的第一个技能

创建你的第一个技能

此示例创建一个教 Claude 使用视觉图表和类比来解释代码的技能。由于它使用默认前置元数据,Claude 可以在你询问某事如何工作时自动加载它,或者你可以使用 /explain-code 直接调用它。

  1. 创建技能目录

在个人的home目录下,创建一个skill的目录,用来存放个人技能

mkdir -p ~/.claude/skills/explain-code
  1. 创建SKILL.md文件

每个技能都需要一个 SKILL.md 文件,包含两部分:YAML 前置元数据(在 — 标记之间)告诉 Claude 何时使用该技能,以及包含 Claude 在调用技能时遵循的说明的 markdown 内容。name 字段变成 /slash-command,description 帮助 Claude 决定何时自动加载它。

---
name: explain-code
description: Explains code with visual diagrams and analogies. Use when explaining how code works, teaching about a codebase, or when the user asks "how does this work?"
---

When explaining code, always include:

1. **Start with an analogy**: Compare the code to something from everyday life
2. **Draw a diagram**: Use ASCII art to show the flow, structure, or relationships
3. **Walk through the code**: Explain step-by-step what happens
4. **Highlight a gotcha**: What's a common mistake or misconception?

Keep explanations conversational. For complex concepts, use multiple analogies.
  1. 测试技能

可以通过两种方式测试它:

让Claude自动调用它,需要询问与描述匹配的内容

How does this code work?

或者直接使用技能名称调用它,搜索/explain会出现,然后Tab进行补充即可

/explain-code src/auth/login.ts

skill可以存放的位置

位置 路径 适用于
企业 参阅托管设置 你的组织中的所有用户
个人 ~/.claude/skills/<skill-name>/SKILL.md 你的所有项目
项目 .claude/skills/<skill-name>/SKILL.md 仅此项目
插件 <plugin>/skills/<skill-name>/SKILL.md 启用插件的位置
提示

当你在子目录中处理文件时,Claude Code 会自动从嵌套的 .claude/skills/ 目录中发现技能。例如,如果你在 packages/frontend/ 中编辑文件,Claude Code 也会在 packages/frontend/.claude/skills/ 中查找技能。这支持单仓库设置,其中包有自己的技能。

每个技能都是一个以SKILL.md作为入口点的目录

my-skill/
├── SKILL.md           # 主要说明(必需)
├── template.md        # Claude 要填写的模板
├── examples/
│   └── sample.md      # 显示预期格式的示例输出
└── scripts/
    └── validate.sh    # Claude 可以执行的脚本

SKILL.md 包含主要说明并且是必需的。其他文件是可选的,让你构建更强大的技能:Claude 要填写的模板、显示预期格式的示例输出、Claude 可以执行的脚本或详细的参考文档。从你的 SKILL.md 中引用这些文件,以便 Claude 知道它们包含什么以及何时加载它们。

使用扁平子目录:将庞大的上下文文件移至标准文件夹。保持文件深度仅为一级(例如,references/schema.md,而不是 references/db/v1/schema.md)

3.2 配置技能

Skill中的技能通过 SKILL.md 顶部的 YAML 前置元数据和随后的 markdown 内容进行配置。

技能内容类型

技能文件可以包含任何说明,但思考你想如何调用它们有助于指导包含的内容

allowed-tools 字段定义 skill 可以在没有用户批准的情况下使用哪些工具,类似于 Claude 的 allowed-tools。

您可以使用通配符来限定权限范围,例如,Bash(git:) 只允许 git 子命令,而 Bash(npm:) 允许所有 npm 操作。skill-creator skill 使用 “Read,Write,Bash,Glob,Grep,Edit” 来赋予它广泛的文件和搜索能力。

  • Glob其实不是一个独立的“工具”,而是一种 通配符/模式匹配机制,它在很多编程语言和工具里都被用来查找文件或路径

  • model 字段定义 skill 可以使用哪个模型。它默认继承用户会话中的当前模型。对于代码审查等复杂任务,skills 可以请求更强大的模型,例如 Claude Opus 或其他 OSS 中文模型。如果你知道就知道。

  • version 字段(例如,version: “1.0.0”)是用于跟踪 skill 版本的元数据字段,从 frontmatter 解析,但主要用于文档和 skill 管理目的。

3.2 SKILL提示词内容

Claude 在调用 skill 时收到的实际提示词。这是您定义 skill 的行为、指令和工作流的地方。编写有效 skill 提示词的关键是保持专注并使用渐进式披露:在 SKILL.md 中提供核心指令,并引用外部文件以获取详细内容。

---
# Frontmatter 在此处
---

# [简短目的陈述 - 1-2 句]

## 概述
[此 skill 的功能、何时使用、提供什么]

## 先决条件
[所需工具、文件或上下文]

## 指令

### 步骤 1:[第一个操作]
[命令式指令]
[如需要,提供示例]

### 步骤 2:[下一个操作]
[命令式指令]

### 步骤 3:[最后操作]
[命令式指令]

## 输出格式
[如何构建结果]

## 错误处理
[失败时该做什么]

## 示例
[具体使用示例]

## 资源
[如果捆绑,引用 scripts/、references/、assets/]
  • 使用 {baseDir} 作为路径,永远不要硬编码绝对路径,如 /home/user/project/
  • 使用命令式语言(“分析代码以…”)而不是第二人称(“您应该分析…”)
  • 引用外部文件以获取详细内容,而不是嵌入所有内容

references/ 目录

references/ 目录存储 Claude 在引用时读入其上下文的文档。这是文本内容——markdown 文件、JSON schemas、配置模板或 Claude 完成任务所需的任何文档。


#### 1.4 学习框架文档

**加载并阅读以下参考文件:**

- **MCP 最佳实践:** [📋 查看最佳实践](./reference/mcp_best_practices.md) - 所有 MCP 服务器的核心指南

**对于 Python 实现,还要加载:**
- **Python SDK 文档:** 使用 WebFetch 加载 `https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/main/README.md`
- [🐍 Python 实现指南](./reference/python_mcp_server.md) - Python 特定的最佳实践和示例

**对于 Node/TypeScript 实现,还要加载:**
- **TypeScript SDK 文档:** 使用 WebFetch 加载 `https://raw.githubusercontent.com/modelcontextprotocol/typescript-sdk/main/README.md`
- [⚡ TypeScript 实现指南](./reference/node_mcp_server.md) - Node/TypeScript 特定的最佳实践和示例

当 Claude 遇到这些指令时,它使用 Read 工具:Read({baseDir}/references/mcp_best_practices.md)。内容被加载到 Claude 的上下文中,提供详细信息而不会使 SKILL.md 变得混乱。

assets目录

assets/ 目录包含 Claude 按路径引用但不加载到上下文中的模板和二进制文件。将其视为 skill 的静态资源——HTML 模板、CSS 文件、图像、配置样板或字体。

使用 {baseDir}/assets/report-template.html 的模板作为报告结构。
引用 {baseDir}/assets/diagram.png 的架构图。

4. 常见Skill 模式

4.1 脚本自动化

将计算任务卸载到scripts/目录中的Python脚本或Bash脚本skill 提示词告诉 Claude 执行脚本并处理其输出

skill.md Instructions ----> Python/Bash script ----> Deterministic Logic ----> Output---->Claude Process
在目标目录上运行 scripts/analyzer.py:

`python {baseDir}/scripts/analyzer.py --path "$USER_PATH" --output report.json`

解析生成的 `report.json` 并呈现发现。

4.2 读写-处理-写入

用于文件转换和数据处理

最简单的模式——读取输入,按照指令转换,写入输出。用于格式转换、数据清理或报告生成。

4.3 搜索-分析-报告

使用 Grep 搜索代码库中的模式,读取匹配文件以获取上下文,分析发现,并生成结构化报告。或者,搜索企业数据存储以获取数据,分析检索到的数据以获取信息,并生成结构化报告。

## 分析过程
1. 使用 Grep 查找相关代码模式
2. 读取每个匹配的文件
3. 分析漏洞
4. 生成结构化报告

4.4 命令链执行

用例: 具有依赖关系的多步骤操作。

执行一系列命令,其中每个步骤都依赖于前一个步骤的成功。常见于类似 CI/CD 的工作流。

cc model

  • 向导式多步骤工作流
  • 基于模板的生成
  • 迭代细化
  • 上下文聚合

5. 实际案例

    1. 顶部(必读):使用场景、触发条件
    1. 中部(流程):具体工作步骤
    1. 底部(参考):API文档,详细说明
  1. 帮我整理Downloads文件夹
**执行流程**  
1. 扫描 Downloads 文件夹
2. 识别文件类型
3. 创建分类文件夹

**输出结果**

超简洁的SKILL类型

----
name:
description:
----
适用场景:简单指令,规则列表
模板:

# 技能标题

执行任务时,遵循以下规则:
1. 规则1
2. 规则2
3. 规则3

## 注意事项
- 注意事项1
- 注意事项2
- 注意事项3

实际案例;explaining-code

  1. 流程型(1000-1500字)

适用于场景:多步骤任务,工作流程

---
name:
description:
---

# 技能标题

## 使用场景
- 场景一:
- 场景二:

## 核心功能
1. 功能1
2. 功能2
3. 功能3

## 执行流程
### 阶段1:准备
1. 步骤1
2. 步骤2

### 阶段2:执行
1. 步骤1
2. 步骤2

### 阶段3:验证
1. 步骤1
2. 步骤2

## 示例
### 示例1

实际案例:file-organizer,lead-research-assistant

  1. API/技术类型(1000-2000字)

使用场景:调用外部API,需技术配置

---
name:aip-skill
description:
---

# 技能标题
## 概述

[简要说明这个API的用途和优势]

## 使用场景
- 场景一:
- 场景二:

## 前置要求
### 环境变量

6. 文件命名和技巧

6.1 文件命名

  1. 目录命名

规则:全小写,用连字符分隔 article-translate,file-organizer

  1. YAML name 字段 必须与目录名完全一致

  2. 描述字段写作:用第三人称,完整句子

6.2 文件组织策略

  1. 什么时候创建scripts/?

需要脚本的情况:

  • 代码会被反复调用
  • 确定性执行结果
  • 逻辑复杂
  1. 什么时候创建references/?

需要文档的情况:

  • 需要详细说明
  • 需要引用外部文档
  • 需要提供上下文
  1. 什么时候创建assets/?
  • 输出模板
  • 图片、文字、字体、样式表
  • 文件模板

7. 利用LLM进行SKILL的验证和优化

LLM使用自己的skills,最好的确认方式就是和LLM交互来优化验证skill

  1. 发现验证

Agent严格根据 YAML 前置元数据加载技能。请单独测试 LLM 如何解读您的描述,以防止误触发(例如,当目标应用是 Angular 时,却触发了 React 应用的请求)。

例如把下面的内容复制到LLM的chat中去

I am building an Agent Skill based on the agentskills.io spec. Agents will decide whether to load this skill based entirely on the YAML metadata below.

name: angular-vite-migrator
description: Migrates Angular CLI projects from Webpack to Vite and esbuild. Use when the user wants to update builder configurations, replace webpack plugins with rollup equivalents, or speed up Angular compilation.

Based strictly on this description:

  1. Generate 3 realistic user prompts that you are 100% confident should trigger this skill.
  2. Generate 3 user prompts that sound similar but should NOT trigger this skill (e.g., migrating a React app to Vite, or just updating Angular versions).
  3. Critique the description: Is it too broad? Suggest an optimized rewrite.

利用LLM来生成相互验证的prompt

  1. Logic 验证

确保您的步骤说明是确定性的,不要让智能体误以为缺少某些步骤。 将完整的 SKILL.md 文件和目录结构提供给 LLM

[Paste your SKILL.md contents here] Act as an autonomous agent that has just triggered this skill. Simulate your execution step-by-step based on a request to Migrate my Angular v17 app to Vite.

For each step, write out your internal monologue:

What exactly are you doing?
Which specific file/script are you reading or running?
Flag any Execution Blockers: Point out the exact line where you are forced to guess or hallucinate because my instructions are ambiguous (e.g., how to map Angular environment files to Vite's import.meta.env).
  1. 边缘案例测试

强制 LLM 查找 Web 工具固有的漏洞、不受支持的配置和故障状态。

使用LLM攻击你的逻辑:

Now, switch roles. Act as a ruthless QA tester. Your goal is to break this skill. Ask me 3 to 5 highly specific, challenging questions about edge cases, failure states, or missing fallbacks in the SKILL.md. Focus on:
  1. 架构细化

LLM(层级管理)通常会尝试将大型配置文件直接塞入主提示符中。使用此步骤可以强制执行渐进式披露并缩小令牌占用空间。

提示

Based on my answers to your edge-case questions, rewrite the SKILL.md file, strictly enforcing the Progressive Disclosure design pattern:

  1. Keep the main SKILL.md strictly as a high-level set of steps using third-person imperative commands (e.g., Execute the esbuild script, Read the Vite config template).
  2. If there are dense rules, large vite.config.ts templates, or complex angular.json schemas currently in the file, remove them. Tell me to create a new file in references/ or assets/, and replace the text in SKILL.md with a strict command to read that specific file only when needed.
  3. Add a dedicated Error Handling section at the bottom incorporating my answers about Webpack fallbacks and CommonJS resolution.