Welcome back! ๐
In Chapter 2: Skill Command Structure, we defined the "ID Card" that every skill must have. We know what a skill is. Now, we need to answer: Where do they live?
In this chapter, we will explore Skill Sources & Scoping.
Imagine you are a software engineer working on two different projects: a website for a Bank and a game for a Startup.
Just like variable scope in programming (Global vs. Local variables), we categorize skills based on where they are stored:
The system uses a concept called SkillSource to define these locations. Here are the three main sources you will see in the code:
userSettings:~/.claude/skills (your home directory).projectSettings:.claude/skills (inside your current working folder).policySettings:When the application starts, it looks at the file system layers to build your toolbox.
Let's look at how the code handles these different locations.
In the code, we don't just use random strings. We define a specific type to ensure we only look in valid places.
// utils/settings/constants.ts (Simplified)
export type SettingSource =
| 'projectSettings' // Local folder
| 'userSettings' // Global home dir
| 'policySettings'; // Corporate rules
Explanation: This TypeScript definition restricts the application. It prevents us from accidentally trying to load skills from a temporary folder or an invalid location.
How does the code know where .claude/skills is? We use a helper function to calculate the file path based on the source.
// skills/loadSkillsDir.ts
export function getSkillsPath(source, type) {
// If local, look in the current working directory
if (source === 'projectSettings') {
return path.join(process.cwd(), '.claude', type);
}
// If global, look in the user's home directory
return path.join(os.homedir(), '.claude', type);
}
Explanation:
process.cwd(): Gets the folder you are currently typing in (Current Working Directory).os.homedir(): Gets your main user folder (e.g., C:\Users\Name or /Users/Name).
This ensures that projectSettings change as you move folders, but userSettings stay constant.
In Chapter 1: Skills Menu Interface, we saw the menu rendering code. Now we can fully understand how it groups these items using the source we identified.
// SkillsMenu.tsx
// 1. Create buckets for each source
const groups = {
projectSettings: [],
userSettings: [],
policySettings: []
};
// 2. Sort skills into buckets
for (const skill of skills) {
// skill.source was determined when the file was loaded
if (skill.source in groups) {
groups[skill.source].push(skill);
}
}
Explanation:
The SkillsMenu doesn't need to know file paths. It simply trusts the skill.source property. This separation of concerns is excellent design: the Loader figures out paths, and the Menu just displays the category.
The menu helps the user distinguish between these sources visually.
// SkillsMenu.tsx
function getSourceTitle(source) {
// Converts 'projectSettings' -> 'Project skills'
return `${capitalize(getSettingSourceName(source))} skills`;
}
Explanation:
This small utility function transforms the internal variable name (projectSettings) into a friendly title for the user interface ("Project skills"), making the list easy to read.
Understanding scoping solves the "Collision" problem.
If you have a skill named test in your User settings, and a skill named test in your Project settings, the application needs to know they are different (or which one takes priority).
By explicitly tracking the source, the UI can:
In this chapter, we learned:
process.cwd() and os.homedir().Now we have skills loaded from files on your computer. But what if a skill doesn't come from a file at all? What if it comes from a live AI server running somewhere else?
Next Chapter: MCP (Model Context Protocol) Integration
Generated by Code IQ