How to Create and Manage Skills for Claudian: File Structure, Storage, and API Guide
Claudian skills are custom slash commands stored as markdown files in /.claude/skills/<name>/SKILL.md that support YAML front-matter configuration for model invocation control, user permissions, and tool access.
Claudian implements a robust skill management system that treats specialized prompts as first-class executable units within Obsidian. Unlike standard slash commands, skills support advanced configuration options including sub-agent forking, restricted tool access, and invocation control, all persisted through a decoupled storage layer. This article explores the complete lifecycle of Claudian skills—from authoring the SKILL.md files to programmatic manipulation via the TypeScript API.
Understanding the Skill Architecture
Claudian organizes skill management into five distinct layers, each handled by specific modules in the codebase:
| Layer | Responsibility | Source File |
|---|---|---|
| File format | YAML front-matter + prompt body | src/utils/frontmatter.ts |
| Parsing | Converts markdown to SlashCommand objects |
src/utils/slashCommand.ts |
| Storage | Vault I/O operations via loadAll, save, delete |
src/core/storage/SkillStorage.ts |
| UI | Modal dialogs and settings interfaces | src/features/settings/ui/SlashCommandSettings.ts |
| Type definitions | Interface definitions with skill-specific fields | src/core/types/settings.ts |
Skills differ from regular slash commands in that they default to model-only invocation unless explicitly configured otherwise. The separation of concerns ensures that malformed individual skills never crash the entire system during loading.
Skill File Structure and Format
Every skill resides in its own directory under the vault root, following a strict naming convention:
/.claude/skills/
├─ my-skill/
│ └─ SKILL.md
The SKILL.md file must begin with a YAML front-matter block delimited by triple dashes. This metadata controls execution behavior and supports both kebab-case and camelCase key variants:
| Front-matter key | Type | Purpose |
|---|---|---|
description |
string | Human-readable summary shown in UI |
disable-model-invocation / disableModelInvocation |
boolean | Prevents Claude from auto-invoking the skill |
user-invocable / userInvocable |
boolean | Allows manual user triggering via /skill-name |
context |
string | Set to fork to run in isolated sub-agent |
agent |
string | Sub-agent name when using context: fork |
allowed-tools |
string[] | Whitelist of tools (Bash, Read, Write, etc.) |
hooks |
object | Arbitrary JSON passed to Claude SDK |
The content following the closing --- serves as the prompt template. Use $ARGUMENTS as a placeholder for dynamic input.
Example skill definition (.claude/skills/commit/SKILL.md):
---
description: Commit staged changes
disable-model-invocation: true
user-invocable: false
allowed-tools:
- Bash
model: sonnet
---
Commit the staged files with the message:
$ARGUMENTS
Parsing and Loading Skills
When Claudian initializes, SkillStorage.loadAll() traverses the /.claude/skills/ directory and processes each SKILL.md through parseSlashCommandContent in src/utils/slashCommand.ts.
The parser handles normalization between kebab-case file formats and camelCase internal properties:
// src/utils/slashCommand.ts
disableModelInvocation:
extractBoolean(fm, 'disable-model-invocation') ??
extractBoolean(fm, 'disableModelInvocation'),
userInvocable:
extractBoolean(fm, 'user-invocable') ??
extractBoolean(fm, 'userInvocable'),
context: extractString(fm, 'context') === 'fork' ? 'fork' : undefined,
agent: extractString(fm, 'agent'),
hooks: isRecord(fm.hooks) ? fm.hooks : undefined,
The parseFrontmatter utility in src/utils/frontmatter.ts provides fallback tolerant parsing, ensuring that YAML syntax errors in one skill do not prevent others from loading. Individual file errors are caught and silently skipped during the loadAll() operation.
Storage Layer Operations
The SkillStorage class in src/core/storage/SkillStorage.ts abstracts vault file system operations through three primary methods:
loadAll()- Returns an array ofSlashCommandobjects by reading everySKILL.mdin/.claude/skills/. Errors in specific files are isolated and logged without breaking the bulk operation.save(skill)- Serializes aSlashCommandto markdown using kebab-case keys, creates the necessary folder structure viaensureFolder, and writes toSKILL.md.delete(skillId)- Removes theSKILL.mdfile and its containing directory usingdeleteFolder.
All paths are relative to the vault root, and the storage layer guarantees atomic folder creation before file writes.
Creating and Editing Skills via UI
The settings interface (src/features/settings/ui/SlashCommandSettings.ts) manages skills through the SlashCommandModal component. When creating a new skill via the + button:
- Select "Type: Skill" from the dropdown to reveal skill-specific toggles
- Configure "Disable model invocation" and "Disable user invocation" checkboxes
- Set "Context" to
forkand specify an "Agent" if running isolated sub-agents - Input the prompt body directly or write raw front-matter in the markdown textarea
The modal uses parseSlashCommandContent to validate inline front-matter entries, allowing power users to author skills entirely within the text editor. When saving, the UI constructs a SlashCommand object with source: 'user' and persists it via storage.skills.save().
Converting Commands to Skills
Existing slash commands can be promoted to skills through the "Convert to skill" button in SlashCommandSettings. The transformation logic (transformToSkill, lines 27-55) performs:
- Name sanitization - Converts the command name to lowercase alphanumerics with hyphens
- Property migration - Copies description and content, sets
id: 'skill-<name>'andsource: 'user' - Atomic replacement - Saves the new skill via
storage.skills.save()and deletes the original command file
This one-click migration preserves the original prompt logic while unlocking skill-specific capabilities like invocation controls and tool restrictions.
Programmatic Skill Management
Developers can manage skills directly through the storage API for automation or plugin integration:
import { SkillStorage } from '@/core/storage/SkillStorage';
import type { VaultFileAdapter } from '@/core/storage/VaultFileAdapter';
import type { SlashCommand } from '@/core/types';
// Initialize with your VaultFileAdapter instance
const skillStorage = new SkillStorage(adapter);
// Retrieve all skills
const allSkills: SlashCommand[] = await skillStorage.loadAll();
// Create a skill programmatically
const newSkill: SlashCommand = {
id: 'skill-quick-note',
name: 'quick-note',
description: 'Create a short note from the model',
content: 'Write a concise note about: $ARGUMENTS',
disableModelInvocation: true,
userInvocable: true,
source: 'user',
};
await skillStorage.save(newSkill);
// Remove a skill
await skillStorage.delete('skill-quick-note');
This API enables dynamic skill generation, bulk imports, or conditional skill registration based on vault state.
End-to-End Implementation Example
Step 1: Manual file creation
Create .claude/skills/todo/SKILL.md:
---
description: Add a todo item to the user's TODO file
disable-model-invocation: true
user-invocable: true
allowed-tools:
- Read
- Write
---
Add a new todo entry:
$ARGUMENTS
Step 2: Runtime loading
const skills = await plugin.storage.skills.loadAll();
const todoSkill = skills.find(s => s.name === 'todo');
console.log('Skill loaded:', todoSkill?.description);
Step 3: Model invocation
When Claude generates a tool-use request:
{
"type": "tool_use",
"name": "Skill",
"input": { "skill": "todo", "arguments": "Buy groceries" }
}
Claudian substitutes $ARGUMENTS with "Buy groceries", restricts execution to Read and Write tools, and prevents the model from recursively invoking the skill due to disable-model-invocation: true.
Summary
- Skills are defined in
/.claude/skills/<name>/SKILL.mdwith YAML front-matter controlling execution permissions and tool access - The
SkillStorageclass insrc/core/storage/SkillStorage.tsprovidesloadAll(),save(), anddelete()methods with error isolation parseSlashCommandContentinsrc/utils/slashCommand.tsnormalizes kebab-case file syntax to camelCase internal properties- The settings UI (
SlashCommandSettings) supports both visual editing and raw markdown input for skill creation - Regular slash commands convert to skills via
transformToSkill, which handles ID generation and atomic file replacement - Programmatic API access enables dynamic skill management for plugin developers and automation scripts
Frequently Asked Questions
What is the difference between a slash command and a skill in Claudian?
A standard slash command is a user-triggered prompt, while a skill is a specialized command that can be restricted to model-only invocation, limited to specific tools, and executed in forked sub-agent contexts. Skills support additional front-matter keys like disable-model-invocation and context that regular commands lack, and they are stored in dedicated SKILL.md files rather than the general commands directory.
How do I prevent the Claude model from automatically calling a skill?
Set disable-model-invocation: true (or disableModelInvocation: true) in the skill's front-matter. According to src/utils/slashCommand.ts, this boolean flag maps to the disableModelInvocation property on the SlashCommand object, which the execution layer checks before allowing tool-use requests.
Can skills be organized in subdirectories within /.claude/skills/?
The current implementation in src/core/storage/SkillStorage.ts expects each skill to reside in its own immediate subdirectory under /.claude/skills/<skill-name>/SKILL.md. While loadAll() walks the directory tree, the standard UI operations assume a flat structure where the folder name matches the skill identifier. For complex organizations, use the programmatic API with custom path handling.
What happens if a SKILL.md file contains invalid YAML?
The parseFrontmatter utility in src/utils/frontmatter.ts implements fallback tolerant parsing. If front-matter extraction fails, SkillStorage.loadAll() catches the error for that specific file and continues loading remaining skills. The malformed file is silently skipped rather than crashing the entire skill registry, ensuring system stability.
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 →