Overview
Skill registration is the process of making skills available to AI agents through the FastSkill service. Skills can be registered manually through the API or discovered automatically from the filesystem.
Once registered, skills become available for discovery, routing, and execution by AI agents and frameworks.
Before registering a skill, you need to understand the skill definition format. Each skill is defined by a JSON object with specific required and optional fields:
Required Fields
Unique identifier for the skill. Must be alphanumeric with dashes and underscores only. Example: "text-processor", "pdf-extractor-v2".
Human-readable name for the skill. Should be descriptive and user-friendly. Example: "Text Processing Suite", "PDF Document Extractor".
Detailed description of what the skill does and its capabilities. Used for discovery and routing.
Version number following semantic versioning (e.g., “1.0.0”, “2.1.3”). Helps track skill evolution and compatibility.
Optional Fields
Name or organization of the skill creator. Useful for skill attribution and support.
Comma-separated list of tags for categorization. Example: "text,nlp,analysis,extraction".
Comma-separated list of specific capabilities. Example: "text_extraction,sentiment_analysis,keyword_detection".
Path to the skill implementation file (relative to storage path). Example: "text-processor/SKILL.md".
Whether the skill is enabled for use. Defaults to true. Disabled skills are not available for discovery or execution.
Maximum execution time in seconds for this skill. Overrides the global default.
Memory limit in MB for skill execution. Overrides the global default.
List of dependencies required by the skill. Example: ["serde", "tokio", "reqwest"].
Additional metadata as key-value pairs. Useful for custom extensions.
Manual Registration
Rust API
Create skill definition
use fastskill :: { SkillDefinition , SkillId };
let mut skill = SkillDefinition :: new (
SkillId :: new ( "text-processor" . to_string ()) ? ,
"Text Processing Suite" . to_string (),
"Comprehensive text processing capabilities including extraction, analysis, and transformation" . to_string (),
"1.0.0" . to_string (),
);
skill . author = Some ( "FastSkill Team" . to_string ());
skill . tags = vec! [
"text" . to_string (),
"nlp" . to_string (),
"analysis" . to_string (),
"extraction" . to_string (),
"transformation" . to_string (),
];
skill . capabilities = vec! [
"text_extraction" . to_string (),
"text_analysis" . to_string (),
"sentiment_analysis" . to_string (),
"keyword_extraction" . to_string (),
"text_transformation" . to_string (),
];
skill . skill_file = std :: path :: PathBuf :: from ( "text-processor/SKILL.md" );
skill . enabled = true ;
skill . timeout = Some ( 30 );
skill . dependencies = Some ( vec! [
"nltk" . to_string (),
"spacy" . to_string (),
]);
Register the skill
use fastskill :: { FastSkillService , ServiceConfig };
use std :: path :: PathBuf ;
#[tokio :: main]
async fn main () -> Result <(), Box < dyn std :: error :: Error >> {
let config = ServiceConfig {
skill_storage_path : PathBuf :: from ( "./skills" ),
.. Default :: default ()
};
let mut service = FastSkillService :: new ( config ) . await ? ;
service . initialize () . await ? ;
// Register the skill (using skill from previous step)
let skill_id = service . skill_manager () . register_skill ( skill ) . await ? ;
println! ( "✅ Skill registered with ID: {}" , skill_id );
// Verify registration
let skills = service . skill_manager () . list_skills ( None ) . await ? ;
println! ( "📋 Total skills: {}" , skills . len ());
service . shutdown () . await ? ;
Ok (())
}
Update existing skill
use fastskill :: { FastSkillService , ServiceConfig , SkillId , SkillUpdate };
use std :: path :: PathBuf ;
#[tokio :: main]
async fn main () -> Result <(), Box < dyn std :: error :: Error >> {
let config = ServiceConfig {
skill_storage_path : PathBuf :: from ( "./skills" ),
.. Default :: default ()
};
let mut service = FastSkillService :: new ( config ) . await ? ;
service . initialize () . await ? ;
let skill_id = SkillId :: new ( "text-processor" . to_string ()) ? ;
// Update skill definition
let updates = SkillUpdate {
name : Some ( "Advanced Text Processing Suite" . to_string ()),
description : Some ( "Enhanced text processing with AI-powered analysis" . to_string ()),
version : Some ( "1.1.0" . to_string ()),
tags : Some ( vec! [
"text" . to_string (),
"nlp" . to_string (),
"analysis" . to_string (),
"ai" . to_string (),
]),
capabilities : Some ( vec! [
"text_extraction" . to_string (),
"text_analysis" . to_string (),
"ai_analysis" . to_string (),
]),
.. Default :: default ()
};
// Update the skill
service . skill_manager ()
. update_skill ( & skill_id , updates )
. await ? ;
println! ( "✅ Skill updated successfully" );
service . shutdown () . await ? ;
Ok (())
}
REST API
# Register a skill via REST API
curl -X POST http://localhost:8080/api/skills \
-H "Content-Type: application/json" \
-d '{
"id": "text-processor",
"name": "Text Processing Suite",
"description": "Comprehensive text processing capabilities",
"version": "1.0.0",
"tags": "text,nlp,analysis",
"capabilities": "text_extraction,text_analysis",
"enabled": true
}'
Auto-Discovery
FastSkill can automatically discover and register skills from the filesystem:
Directory Structure
Organize your skills in a directory structure like this:
skills/
├── text-processor/
│ ├── SKILL.md # Skill definition (Claude Code format)
│ ├── script.sh # Implementation script (optional)
│ └── README.md # Documentation
├── data-analyzer/
│ ├── SKILL.md
│ └── README.md
└── web-scraper/
├── SKILL.json
├── scraper.py
└── config.yaml
Enable Auto-Discovery
Configure auto-discovery
// Auto-discovery happens automatically when service initializes
// Skills are discovered from the skill_storage_path directory
// The service scans for SKILL.md files during initialization
Batch Operations
Register multiple skills efficiently:
Rust Batch Registration
use fastskill :: { FastSkillService , ServiceConfig , SkillDefinition , SkillId };
use std :: path :: PathBuf ;
#[tokio :: main]
async fn main () -> Result <(), Box < dyn std :: error :: Error >> {
let config = ServiceConfig {
skill_storage_path : PathBuf :: from ( "./skills" ),
.. Default :: default ()
};
let mut service = FastSkillService :: new ( config ) . await ? ;
service . initialize () . await ? ;
// Define multiple skills
let skills_to_register = vec! [
SkillDefinition :: new (
SkillId :: new ( "text-extractor" . to_string ()) ? ,
"Text Extractor" . to_string (),
"Extract text from various document formats" . to_string (),
"1.0.0" . to_string (),
),
SkillDefinition :: new (
SkillId :: new ( "data-validator" . to_string ()) ? ,
"Data Validator" . to_string (),
"Validate and clean data structures" . to_string (),
"1.0.0" . to_string (),
),
SkillDefinition :: new (
SkillId :: new ( "file-organizer" . to_string ()) ? ,
"File Organizer" . to_string (),
"Organize files by type and content" . to_string (),
"1.0.0" . to_string (),
),
];
// Register all skills
let mut registered_ids = Vec :: new ();
for skill in skills_to_register {
match service . skill_manager () . register_skill ( skill ) . await {
Ok ( skill_id ) => {
registered_ids . push ( skill_id . clone ());
println! ( "✅ Registered: {}" , skill_id );
}
Err ( e ) => {
eprintln! ( "❌ Failed to register skill: {}" , e );
}
}
}
println! ( " \n 🎯 Successfully registered {} skills" , registered_ids . len ());
service . shutdown () . await ? ;
Ok (())
}
Batch Update
use fastskill :: { FastSkillService , ServiceConfig , SkillId , SkillUpdate };
use std :: path :: PathBuf ;
#[tokio :: main]
async fn main () -> Result <(), Box < dyn std :: error :: Error >> {
let config = ServiceConfig {
skill_storage_path : PathBuf :: from ( "./skills" ),
.. Default :: default ()
};
let mut service = FastSkillService :: new ( config ) . await ? ;
service . initialize () . await ? ;
// Define updates for multiple skills
let updates = vec! [
(
SkillId :: new ( "text-extractor" . to_string ()) ? ,
SkillUpdate {
version : Some ( "1.0.1" . to_string ()),
timeout : Some ( 60 ),
.. Default :: default ()
},
),
(
SkillId :: new ( "file-organizer" . to_string ()) ? ,
SkillUpdate {
version : Some ( "1.0.1" . to_string ()),
timeout : Some ( 60 ),
.. Default :: default ()
},
),
];
for ( skill_id , update_data ) in updates {
match service . skill_manager () . update_skill ( & skill_id , update_data ) . await {
Ok ( _ ) => println! ( "✅ Updated {}" , skill_id ),
Err ( e ) => eprintln! ( "❌ Failed to update {}: {}" , skill_id , e ),
}
}
service . shutdown () . await ? ;
Ok (())
}
Validation
FastSkill validates skill definitions before registration:
Manual validation
use fastskill :: { FastSkillService , ServiceConfig , SkillDefinition , SkillId };
use std :: path :: PathBuf ;
#[tokio :: main]
async fn main () -> Result <(), Box < dyn std :: error :: Error >> {
let config = ServiceConfig {
skill_storage_path : PathBuf :: from ( "./skills" ),
.. Default :: default ()
};
let mut service = FastSkillService :: new ( config ) . await ? ;
service . initialize () . await ? ;
// Create skill definition
let skill = SkillDefinition :: new (
SkillId :: new ( "my-skill" . to_string ()) ? ,
"My Skill" . to_string (),
"A test skill" . to_string (),
"1.0.0" . to_string (),
);
// Validation happens automatically during registration
// Register the skill (will validate internally)
match service . skill_manager () . register_skill ( skill ) . await {
Ok ( skill_id ) => {
println! ( "✅ Skill definition is valid" );
println! ( "✅ Registered: {}" , skill_id );
}
Err ( e ) => {
eprintln! ( "❌ Validation/registration failed: {}" , e );
// Fix the issues before registering
}
}
service . shutdown () . await ? ;
Ok (())
}
Batch validation
use fastskill :: { FastSkillService , ServiceConfig , SkillDefinition , SkillId };
use std :: path :: PathBuf ;
#[tokio :: main]
async fn main () -> Result <(), Box < dyn std :: error :: Error >> {
let config = ServiceConfig {
skill_storage_path : PathBuf :: from ( "./skills" ),
.. Default :: default ()
};
let mut service = FastSkillService :: new ( config ) . await ? ;
service . initialize () . await ? ;
// Define skills to validate and register
let skills_to_validate = vec! [
SkillDefinition :: new (
SkillId :: new ( "skill1" . to_string ()) ? ,
"Skill 1" . to_string (),
"First skill" . to_string (),
"1.0.0" . to_string (),
),
SkillDefinition :: new (
SkillId :: new ( "skill2" . to_string ()) ? ,
"Skill 2" . to_string (),
"Second skill" . to_string (),
"1.0.0" . to_string (),
),
];
let mut valid_count = 0 ;
let mut invalid_count = 0 ;
for skill in skills_to_validate {
match service . skill_manager () . register_skill ( skill ) . await {
Ok ( _ ) => {
valid_count += 1 ;
}
Err ( _ ) => {
invalid_count += 1 ;
}
}
}
println! ( "✅ Valid skills: {}" , valid_count );
println! ( "❌ Invalid skills: {}" , invalid_count );
service . shutdown () . await ? ;
Ok (())
}
CLI Registration
Use the FastSkill CLI for command-line registration:
# Register a skill from JSON file
fastskill register ./skills/text-processor/skill.json
# Register from directory (auto-discovery)
fastskill register --auto ./skills/
# Register with validation
fastskill register --validate ./skill.json
# Batch register multiple files
fastskill register ./skills/ ** / * .json
Best Practices
Use descriptive identifiers
Choose skill IDs that are descriptive and likely to be unique. Include version numbers for skill variants.
Provide comprehensive metadata
Include detailed descriptions, relevant tags, and specific capabilities to improve discoverability.
Version properly
Use semantic versioning and update versions when making breaking changes or adding new features.
Validate before registration
Always validate skill definitions before registering them to catch issues early.
Use auto-discovery for development
Enable auto-discovery during development for faster iteration, but use manual registration in production.
Troubleshooting
Duplicate ID : Each skill must have a unique ID. Check if a skill with the same ID already exists.# Check existing skills
existing_skills = await service.list_skills()
existing_ids = [s[ 'id' ] for s in existing_skills]
Invalid format : Ensure all required fields are present and have the correct types.# Use validation before registration
validate_skill_definition(skill_data)
File not found : If using skill_file, ensure the path exists relative to the storage directory.
Pattern matching : Auto-discovery uses glob patterns. Ensure your files match the configured patterns.
Permission denied : Check that FastSkill has read permissions for skill directories.
Debug discovery : Enable debug logging to see which files are being discovered and why others are skipped.
Performance Considerations
Skill registration is the foundation of FastSkill’s functionality. Take time to understand the skill definition format and validation requirements to avoid common issues.