Where Custom Skill Definitions Are Stored in Craft Agents
Custom skill definitions in Craft Agents are stored as SKILL.md files inside workspace-specific subdirectories located at <workspace-root>/skills/<skill-slug>/, with metadata and content parsed from front-matter and markdown body.
In the craft-ai-agents/craft-agents-oss repository, custom skills are persisted locally on the filesystem rather than in a centralized database. Each workspace maintains its own isolated skills directory containing sub-folders named after their respective skill slugs. Understanding this storage architecture is essential for debugging skill loading issues or implementing custom tooling around the Craft Agents platform.
Workspace Skill Storage Location
Every workspace in Craft Agents has a dedicated root directory. Within that directory, custom skills reside in a predefined skills folder.
The absolute path convention follows this structure:
<workspace-root>/skills/<skill-slug>/SKILL.md
According to the source code in packages/shared/src/workspaces/storage.ts, the function getWorkspaceSkillsPath() returns the absolute path to this skills directory by appending /skills to the workspace root【#84-L89】. This design ensures that skills are scoped per workspace, preventing namespace collisions between different projects.
How Skills Are Structured on Disk
The SKILL.md File Format
Each custom skill is a subdirectory containing a mandatory SKILL.md file. This file serves as the single source of truth for the skill's definition, combining YAML front-matter for metadata and markdown for the implementation body.
The loadWorkspaceSkills() function and related utilities in packages/shared/src/skills/storage.ts read these files to populate the skill registry at runtime【#87-L90】. The metadata structure conforms to the SkillMetadata interface defined in packages/shared/src/skills/types.ts, which standardizes fields like name, description, and configuration parameters.
Supporting Assets
Skills may include additional assets such as icons. The getSkillIconPath() utility looks for icon.* files located alongside SKILL.md within the skill directory【#78-L86】. This colocation pattern keeps all skill-related assets bundled together for easy portability and version control.
Programmatic Access to Skill Storage
The @craft-agents/shared package exports several utilities for interacting with custom skill storage without hardcoding file paths.
Listing Available Skills
To retrieve all skill slugs within a workspace:
import { listSkillSlugs } from '@craft-agents/shared/src/skills/storage';
import { getWorkspacePath } from '@craft-agents/shared/src/workspaces/storage';
const wsId = 'my-workspace';
const wsRoot = getWorkspacePath(wsId);
const slugs = listSkillSlugs(wsRoot);
console.log('Workspace skills:', slugs);
The listSkillSlugs() function scans the <workspace-root>/skills directory and returns an array of directory names representing each skill slug【#35-L40】.
Loading Skill Metadata and Content
To load a specific skill's complete definition:
import { loadSkill } from '@craft-agents/shared/src/skills/storage';
import { getWorkspacePath } from '@craft-agents/shared/src/workspaces/storage';
const wsRoot = getWorkspacePath('my-workspace');
const skill = loadSkill(wsRoot, 'my-custom-skill');
if (skill) {
console.log('Skill name:', skill.metadata.name);
console.log('Description:', skill.metadata.description);
console.log('Body:', skill.content);
}
loadSkill() reads the SKILL.md file for the given slug and parses both the front-matter metadata and the markdown body【#78-L81】.
Resolving Skill Asset Paths
To locate a skill's icon file:
import { getSkillIconPath } from '@craft-agents/shared/src/skills/storage';
import { getWorkspacePath } from '@craft-agents/shared/src/workspaces/storage';
const iconPath = getSkillIconPath(getWorkspacePath('my-workspace'), 'my-custom-skill');
console.log('Icon location:', iconPath);
This utility checks for image files matching icon.* patterns within the skill's directory【#78-L86】.
Key Source Files and Functions
The storage mechanism is implemented across several files in the packages/shared directory:
packages/shared/src/workspaces/storage.ts(lines 84-89): ContainsgetWorkspaceSkillsPath(), which resolves the absolute path to theskillsdirectory for any given workspace.packages/shared/src/skills/storage.ts(lines 78-90): ImplementsloadWorkspaceSkills(),loadSkill(), andgetSkillIconPath(), handling the file system operations for reading skill definitions.packages/shared/src/skills/types.ts: Defines theSkillMetadatainterface that governs the structure of data extracted fromSKILL.mdfront-matter.packages/shared/src/skills/__tests__/storage.test.ts: Contains the test suite demonstrating expected directory structures and validation logic forSKILL.mdfiles.
Summary
- Custom skills are stored per workspace in
<workspace-root>/skills/<skill-slug>/SKILL.md. - The
getWorkspaceSkillsPath()utility provides the canonical path resolution for skill directories. - Each skill directory contains a
SKILL.mdfile with front-matter metadata and optional assets like icons. - Use
listSkillSlugs()to enumerate skills andloadSkill()to read specific definitions. - The storage layer is implemented in
packages/shared/src/skills/storage.tswith type definitions intypes.ts.
Frequently Asked Questions
What happens if a SKILL.md file is missing from a skill directory?
If the SKILL.md file is missing or malformed, the loadSkill() function will return null or throw a parsing error depending on the validation context. The listSkillSlugs() function only returns directory names, so it may list a slug that subsequently fails to load if the file is absent.
Can I store other files in the skill directory besides SKILL.md?
Yes. The directory structure supports additional assets such as icon.* files, which are resolved via getSkillIconPath(). While the system primarily looks for SKILL.md, you can include supplementary files like configuration JSON or documentation, though these require custom loading logic outside the standard skill storage utilities.
How does Craft Agents handle skill name collisions between workspaces?
Since skills are stored within workspace-specific skills directories, collisions are naturally prevented at the storage level. Each workspace operates in isolation, and the getWorkspacePath() function ensures that skill lookups are scoped to the correct workspace root. Skills from different workspaces cannot interfere with each other unless explicitly shared through external synchronization mechanisms.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →