For conceptual information about skills and how they’re used in agents, see Skills Core Concepts.
Overview
The Skills Service enables you to:- List available skills with pagination support
- Get skill details including capabilities, tools, and configurations
- Create custom skills with specific tool sets and capabilities
- Update skill configurations for existing skills
- Delete skills when no longer needed
- Associate skills with entities (agents, teams, etc.)
- Validate skill configurations before deployment
Quick Start
Copy
Ask AI
from kubiya import ControlPlaneClient
# Initialize client
client = ControlPlaneClient(api_key="your-api-key")
# List all available skills
skills = client.skills.list()
for skill in skills:
print(f"Skill: {skill['name']} - Category: {skill.get('category', 'N/A')}")
# Get specific skill details
skill = client.skills.get("skill-uuid")
print(f"Tools: {skill.get('tools', [])}")
List Skills
List all available skills with pagination support.Basic Listing
Copy
Ask AI
# List all skills (first 100)
skills = client.skills.list()
for skill in skills:
print(f"""
Name: {skill['name']}
Category: {skill.get('category', 'N/A')}
Description: {skill.get('description', 'N/A')}
Tools: {len(skill.get('tools', []))} tools
""")
Paginated Listing
Copy
Ask AI
# List skills with pagination
skip = 0
limit = 20
while True:
skills = client.skills.list(skip=skip, limit=limit)
if not skills:
break
for skill in skills:
print(f"Skill: {skill['name']}")
skip += limit
List All Skills
Copy
Ask AI
def list_all_skills():
"""Get all skills across all pages"""
all_skills = []
skip = 0
limit = 100
while True:
skills = client.skills.list(skip=skip, limit=limit)
if not skills:
break
all_skills.extend(skills)
skip += limit
return all_skills
# Usage
all_skills = list_all_skills()
print(f"Total skills: {len(all_skills)}")
Filter Skills by Category
Copy
Ask AI
def filter_skills_by_category(category: str):
"""Filter skills by category"""
all_skills = client.skills.list(limit=1000) # Get all skills
return [s for s in all_skills if s.get('category') == category]
# Usage
cloud_skills = filter_skills_by_category("Cloud")
print(f"Cloud skills: {len(cloud_skills)}")
devops_skills = filter_skills_by_category("DevOps")
print(f"DevOps skills: {len(devops_skills)}")
Get Skill Details
Retrieve detailed information about a specific skill.By Skill ID
Copy
Ask AI
# Get skill by UUID
skill = client.skills.get("skill-uuid-here")
print(f"Skill: {skill['name']}")
print(f"Description: {skill.get('description', 'N/A')}")
print(f"Category: {skill.get('category', 'N/A')}")
print(f"Tools: {skill.get('tools', [])}")
print(f"Capabilities: {skill.get('capabilities', [])}")
Extract Skill Information
Copy
Ask AI
def get_skill_info(skill_id: str):
"""Get comprehensive skill information"""
try:
skill = client.skills.get(skill_id)
info = {
"id": skill.get('uuid'),
"name": skill['name'],
"description": skill.get('description'),
"category": skill.get('category'),
"tools": skill.get('tools', []),
"capabilities": skill.get('capabilities', []),
"required_integrations": skill.get('required_integrations', []),
"configuration": skill.get('configuration', {}),
"enabled": skill.get('enabled', True)
}
return info
except Exception as e:
print(f"Failed to get skill info: {e}")
return None
# Usage
info = get_skill_info("skill-uuid")
if info:
print(f"Skill: {info['name']}")
print(f"Tools: {len(info['tools'])}")
print(f"Capabilities: {info['capabilities']}")
Find Skill by Name
Copy
Ask AI
def find_skill_by_name(name: str):
"""Find a skill by name"""
all_skills = client.skills.list(limit=1000)
for skill in all_skills:
if skill['name'].lower() == name.lower():
return skill
return None
# Usage
kubernetes_skill = find_skill_by_name("kubernetes")
if kubernetes_skill:
print(f"Found skill: {kubernetes_skill['uuid']}")
skill_details = client.skills.get(kubernetes_skill['uuid'])
print(f"Tools: {skill_details.get('tools', [])}")
Create Custom Skill
Create a new custom skill with specific tools and capabilities.Basic Creation
Copy
Ask AI
# Create a custom skill
skill_data = {
"name": "custom-database-admin",
"description": "Database administration tools",
"category": "Database",
"tools": [
{
"name": "query_database",
"description": "Execute database queries",
"type": "shell"
},
{
"name": "backup_database",
"description": "Create database backups",
"type": "shell"
}
],
"capabilities": ["database_query", "database_backup"],
"enabled": True
}
created_skill = client.skills.create(skill_data)
print(f"Created skill: {created_skill['uuid']}")
print(f"Name: {created_skill['name']}")
Create with Integrations
Copy
Ask AI
# Create skill with required integrations
skill_data = {
"name": "aws-infrastructure",
"description": "AWS infrastructure management",
"category": "Cloud",
"tools": [
{
"name": "describe_instances",
"description": "List EC2 instances",
"type": "shell",
"command": "aws ec2 describe-instances"
},
{
"name": "list_s3_buckets",
"description": "List S3 buckets",
"type": "shell",
"command": "aws s3 ls"
}
],
"required_integrations": ["AWS"],
"capabilities": ["cloud_management", "infrastructure_automation"],
"configuration": {
"region": "us-east-1",
"output_format": "json"
}
}
created_skill = client.skills.create(skill_data)
print(f"Created AWS skill: {created_skill['uuid']}")
Create with Validation
Copy
Ask AI
from kubiya.resources.exceptions import SkillError
def create_skill_safe(skill_data: dict):
"""Create skill with pre-validation"""
try:
# Validate configuration first
validation = client.skills.validate(skill_data)
if not validation.get('valid'):
return {
"success": False,
"errors": validation.get('errors', [])
}
# Create skill
skill = client.skills.create(skill_data)
return {
"success": True,
"skill_id": skill['uuid'],
"skill": skill
}
except SkillError as e:
return {
"success": False,
"errors": [str(e)]
}
# Usage
skill_data = {
"name": "custom-monitoring",
"description": "System monitoring tools",
"category": "Monitoring",
"tools": [{"name": "check_health", "type": "shell"}]
}
result = create_skill_safe(skill_data)
if result['success']:
print(f"✅ Created skill: {result['skill_id']}")
else:
print(f"❌ Creation failed: {result['errors']}")
Update Skill
Update an existing skill configuration.Basic Update
Copy
Ask AI
# Update skill settings
skill_id = "skill-uuid-here"
update_data = {
"description": "Updated description",
"enabled": True,
"tools": [
{
"name": "new_tool",
"description": "A new tool",
"type": "shell"
}
]
}
updated_skill = client.skills.update(skill_id, update_data)
print(f"Updated skill: {updated_skill['name']}")
print(f"Description: {updated_skill['description']}")
Add Tools to Skill
Copy
Ask AI
def add_tools_to_skill(skill_id: str, new_tools: list):
"""Add tools to an existing skill"""
# Get current skill
skill = client.skills.get(skill_id)
# Get current tools
current_tools = skill.get('tools', [])
# Add new tools
updated_tools = current_tools + new_tools
# Update skill
update_data = {"tools": updated_tools}
updated_skill = client.skills.update(skill_id, update_data)
return updated_skill
# Usage
new_tools = [
{
"name": "analyze_logs",
"description": "Analyze system logs",
"type": "python"
}
]
updated = add_tools_to_skill("skill-uuid", new_tools)
print(f"Updated skill with {len(updated['tools'])} tools")
Enable/Disable Skill
Copy
Ask AI
def toggle_skill(skill_id: str, enabled: bool):
"""Enable or disable a skill"""
update_data = {"enabled": enabled}
updated_skill = client.skills.update(skill_id, update_data)
status = "enabled" if enabled else "disabled"
print(f"Skill {skill_id} is now {status}")
return updated_skill
# Usage
toggle_skill("skill-uuid", False) # Disable
toggle_skill("skill-uuid", True) # Enable
Delete Skill
Delete a custom skill.Deleting a skill affects any agents or entities using it. Ensure no active agents depend on the skill before deletion.
Copy
Ask AI
# Delete skill
skill_id = "skill-uuid-to-delete"
result = client.skills.delete(skill_id)
print(f"Deletion result: {result}")
Delete with Safety Check
Copy
Ask AI
def delete_skill_safe(skill_id: str):
"""Delete skill with confirmation"""
try:
# Get skill details first
skill = client.skills.get(skill_id)
print(f"About to delete skill: {skill['name']}")
print(f"Category: {skill.get('category')}")
# Perform deletion
result = client.skills.delete(skill_id)
return {
"success": True,
"message": f"Deleted skill: {skill['name']}",
"result": result
}
except SkillError as e:
return {
"success": False,
"message": str(e)
}
# Usage
result = delete_skill_safe("skill-uuid")
if result['success']:
print(f"✅ {result['message']}")
else:
print(f"❌ Deletion failed: {result['message']}")
Associate Skills with Entities
Associate skills with agents, teams, or other entities.Associate Skills with Agent
Copy
Ask AI
# Associate skills with an agent
agent_id = "agent-uuid"
skill_ids = ["skill-uuid-1", "skill-uuid-2", "skill-uuid-3"]
result = client.skills.associate(agent_id, skill_ids)
print(f"Association result: {result}")
Bulk Association
Copy
Ask AI
def associate_skills_bulk(entity_id: str, skill_names: list):
"""Associate skills by name"""
# Find skill IDs by name
all_skills = client.skills.list(limit=1000)
skill_ids = []
for name in skill_names:
for skill in all_skills:
if skill['name'].lower() == name.lower():
skill_ids.append(skill['uuid'])
break
if len(skill_ids) != len(skill_names):
print(f"Warning: Only found {len(skill_ids)} of {len(skill_names)} skills")
# Associate skills
result = client.skills.associate(entity_id, skill_ids)
return result
# Usage
skill_names = ["kubernetes", "terraform", "aws"]
result = associate_skills_bulk("agent-uuid", skill_names)
print(f"Associated {len(skill_names)} skills")
Replace Skills for Entity
Copy
Ask AI
def replace_entity_skills(entity_id: str, new_skill_ids: list):
"""Replace all skills for an entity"""
# Associate new skills (this replaces existing associations)
result = client.skills.associate(entity_id, new_skill_ids)
print(f"Replaced skills for entity {entity_id}")
print(f"New skill count: {len(new_skill_ids)}")
return result
# Usage
new_skills = ["skill-uuid-1", "skill-uuid-2"]
replace_entity_skills("agent-uuid", new_skills)
Validate Skill Configuration
Validate a skill configuration before creation or update.Basic Validation
Copy
Ask AI
# Validate skill configuration
skill_config = {
"name": "test-skill",
"description": "Test skill for validation",
"category": "Testing",
"tools": [
{
"name": "test_tool",
"description": "A test tool",
"type": "shell"
}
],
"capabilities": ["testing"]
}
validation_result = client.skills.validate(skill_config)
if validation_result.get('valid'):
print("✅ Configuration is valid!")
else:
print("❌ Configuration is invalid:")
for error in validation_result.get('errors', []):
print(f" - {error}")
Validate Before Creation
Copy
Ask AI
def create_skill_with_validation(skill_data: dict):
"""Create skill with automatic validation"""
# Validate first
validation = client.skills.validate(skill_data)
if not validation.get('valid'):
return {
"success": False,
"message": "Validation failed",
"errors": validation.get('errors', [])
}
# Create skill
try:
skill = client.skills.create(skill_data)
return {
"success": True,
"message": "Skill created successfully",
"skill_id": skill['uuid'],
"skill": skill
}
except SkillError as e:
return {
"success": False,
"message": "Creation failed",
"errors": [str(e)]
}
# Usage
skill_data = {
"name": "monitoring-alerts",
"category": "Monitoring",
"tools": [{"name": "send_alert", "type": "shell"}]
}
result = create_skill_with_validation(skill_data)
if result['success']:
print(f"✅ {result['message']}: {result['skill_id']}")
else:
print(f"❌ {result['message']}")
for error in result['errors']:
print(f" - {error}")
Practical Examples
1. Skill Discovery System
Copy
Ask AI
def discover_skills(requirements: dict):
"""Discover skills matching requirements"""
all_skills = client.skills.list(limit=1000)
required_capabilities = set(requirements.get('capabilities', []))
required_category = requirements.get('category')
matching_skills = []
for skill in all_skills:
skill_capabilities = set(skill.get('capabilities', []))
skill_category = skill.get('category')
# Check category match
if required_category and skill_category != required_category:
continue
# Check capabilities match
if required_capabilities and not required_capabilities.issubset(skill_capabilities):
continue
# Calculate match score
match_score = len(required_capabilities & skill_capabilities)
matching_skills.append({
"skill": skill,
"match_score": match_score
})
# Sort by match score
matching_skills.sort(key=lambda x: x['match_score'], reverse=True)
return matching_skills
# Usage
requirements = {
"capabilities": ["cloud_management", "automation"],
"category": "Cloud"
}
matches = discover_skills(requirements)
print(f"Found {len(matches)} matching skills:")
for match in matches[:5]: # Top 5
skill = match['skill']
print(f" - {skill['name']} (score: {match['match_score']})")
2. Skill Audit Report
Copy
Ask AI
def generate_skill_audit():
"""Generate audit report of all skills"""
all_skills = client.skills.list(limit=1000)
audit = {
"total_skills": len(all_skills),
"enabled": 0,
"disabled": 0,
"by_category": {},
"tool_count": 0,
"skills_without_description": []
}
for skill in all_skills:
# Count enabled/disabled
if skill.get('enabled', True):
audit['enabled'] += 1
else:
audit['disabled'] += 1
# Count by category
category = skill.get('category', 'Uncategorized')
audit['by_category'][category] = audit['by_category'].get(category, 0) + 1
# Count tools
audit['tool_count'] += len(skill.get('tools', []))
# Track skills without description
if not skill.get('description'):
audit['skills_without_description'].append(skill['name'])
return audit
# Usage
audit = generate_skill_audit()
print(f"Skill Audit Report:")
print(f" Total Skills: {audit['total_skills']}")
print(f" Enabled: {audit['enabled']}")
print(f" Disabled: {audit['disabled']}")
print(f" Total Tools: {audit['tool_count']}")
print(f"\nBy Category:")
for category, count in audit['by_category'].items():
print(f" {category}: {count}")
3. Skill Configuration Manager
Copy
Ask AI
class SkillConfigManager:
"""Helper class for managing skill configurations"""
def __init__(self, client):
self.client = client
def create_from_template(self, template_name: str, custom_config: dict):
"""Create skill from template"""
templates = {
"monitoring": {
"category": "Monitoring",
"capabilities": ["monitoring", "alerting"],
"tools": [
{"name": "check_status", "type": "shell"},
{"name": "send_alert", "type": "shell"}
]
},
"deployment": {
"category": "DevOps",
"capabilities": ["deployment", "automation"],
"tools": [
{"name": "deploy_app", "type": "shell"},
{"name": "rollback", "type": "shell"}
]
}
}
if template_name not in templates:
raise ValueError(f"Unknown template: {template_name}")
# Merge template with custom config
skill_config = {**templates[template_name], **custom_config}
# Validate
validation = self.client.skills.validate(skill_config)
if not validation.get('valid'):
raise ValueError(f"Invalid configuration: {validation.get('errors')}")
# Create skill
skill = self.client.skills.create(skill_config)
return skill
def clone_skill(self, source_skill_id: str, new_name: str):
"""Clone an existing skill"""
# Get source skill
source = self.client.skills.get(source_skill_id)
# Create new skill config
new_config = {
"name": new_name,
"description": f"Cloned from {source['name']}",
"category": source.get('category'),
"tools": source.get('tools', []),
"capabilities": source.get('capabilities', []),
"configuration": source.get('configuration', {})
}
# Create new skill
skill = self.client.skills.create(new_config)
return skill
# Usage
manager = SkillConfigManager(client)
# Create from template
new_skill = manager.create_from_template("monitoring", {
"name": "production-monitoring",
"description": "Production environment monitoring"
})
print(f"Created from template: {new_skill['uuid']}")
# Clone existing skill
cloned = manager.clone_skill("existing-skill-uuid", "cloned-skill-name")
print(f"Cloned skill: {cloned['uuid']}")
4. Skill Dependencies Validator
Copy
Ask AI
def validate_skill_dependencies(skill_config: dict):
"""Validate that all required integrations are available"""
required_integrations = skill_config.get('required_integrations', [])
if not required_integrations:
return {"valid": True, "message": "No dependencies required"}
# Get available integrations
available_integrations = client.integrations.list()
available_names = [i['name'] for i in available_integrations]
missing = []
for required in required_integrations:
if required not in available_names:
missing.append(required)
if missing:
return {
"valid": False,
"message": "Missing required integrations",
"missing": missing
}
return {
"valid": True,
"message": "All dependencies available",
"required": required_integrations
}
# Usage
skill_config = {
"name": "aws-ops",
"required_integrations": ["AWS", "Slack"]
}
deps_check = validate_skill_dependencies(skill_config)
if deps_check['valid']:
print(f"✅ {deps_check['message']}")
else:
print(f"❌ {deps_check['message']}")
print(f"Missing: {deps_check['missing']}")
Error Handling
Copy
Ask AI
from kubiya.resources.exceptions import SkillError
try:
# Try to get a skill
skill = client.skills.get("non-existent-skill")
except SkillError as e:
print(f"Skill error: {e}")
# Handle error - maybe list all skills instead
print("Available skills:")
skills = client.skills.list(limit=10)
for skill in skills:
print(f" - {skill['name']}")
# Create with error handling
try:
skill_data = {
"name": "test-skill",
"category": "Testing"
}
skill = client.skills.create(skill_data)
print(f"Created skill: {skill['uuid']}")
except SkillError as e:
print(f"Creation failed: {e}")
# Validate with error handling
try:
validation = client.skills.validate(skill_data)
if not validation.get('valid'):
print(f"Validation errors: {validation.get('errors')}")
except SkillError as e:
print(f"Validation error: {e}")
Best Practices
1. Always Validate Before Creating
Copy
Ask AI
# Always validate skill configuration before creating
def create_skill_safely(skill_data: dict):
"""Create skill with validation"""
# Validate first
validation = client.skills.validate(skill_data)
if not validation.get('valid'):
raise ValueError(f"Invalid skill configuration: {validation.get('errors')}")
# Create skill
skill = client.skills.create(skill_data)
return skill
# Usage
skill_data = {
"name": "my-skill",
"category": "Custom",
"tools": [{"name": "tool1", "type": "shell"}]
}
try:
skill = create_skill_safely(skill_data)
print(f"✅ Created skill: {skill['uuid']}")
except ValueError as e:
print(f"❌ {e}")
2. Cache Skill Information
Copy
Ask AI
# Cache skills to reduce API calls
class SkillCache:
def __init__(self, client):
self.client = client
self._skills_cache = None
self._skill_details_cache = {}
def get_all_skills(self, force_refresh=False):
"""Get cached skills"""
if self._skills_cache is None or force_refresh:
self._skills_cache = self.client.skills.list(limit=1000)
return self._skills_cache
def get_skill(self, skill_id: str, force_refresh=False):
"""Get cached skill details"""
if skill_id not in self._skill_details_cache or force_refresh:
self._skill_details_cache[skill_id] = self.client.skills.get(skill_id)
return self._skill_details_cache[skill_id]
def invalidate_cache(self):
"""Clear the cache"""
self._skills_cache = None
self._skill_details_cache = {}
# Usage
cache = SkillCache(client)
skills = cache.get_all_skills() # API call
skills_again = cache.get_all_skills() # From cache
3. Use Descriptive Names and Categories
Copy
Ask AI
# Good - descriptive names
skill_data = {
"name": "aws-ec2-management",
"description": "Manage AWS EC2 instances including start, stop, and monitoring",
"category": "Cloud/AWS",
"tools": [...]
}
# Bad - vague names
skill_data = {
"name": "skill1",
"description": "Does stuff",
"category": "Other",
"tools": [...]
}
4. Document Tool Configurations
Copy
Ask AI
# Include clear descriptions for all tools
skill_data = {
"name": "database-admin",
"category": "Database",
"tools": [
{
"name": "query_database",
"description": "Execute SQL queries against the database",
"type": "shell",
"command": "psql -c \"{{query}}\"",
"parameters": [
{
"name": "query",
"description": "SQL query to execute",
"required": True
}
]
}
]
}
API Reference
Methods
| Method | Description | Parameters |
|---|---|---|
list(skip, limit) | List all skills | skip: Records to skip, limit: Max records |
get(skill_id) | Get specific skill | skill_id: Skill UUID |
create(skill_data) | Create custom skill | skill_data: Skill configuration dictionary |
update(skill_id, skill_data) | Update skill | skill_id: UUID, skill_data: Updates |
delete(skill_id) | Delete skill | skill_id: Skill UUID |
associate(entity_id, skill_ids) | Associate skills with entity | entity_id: Entity UUID, skill_ids: List of skill UUIDs |
validate(skill_config) | Validate skill configuration | skill_config: Configuration dictionary |
Skill Object Structure
Copy
Ask AI
{
"uuid": "string", # Unique identifier
"name": "string", # Skill name
"description": "string", # Skill description
"category": "string", # Category (e.g., "Cloud", "DevOps")
"tools": [ # List of tools
{
"name": "string",
"description": "string",
"type": "string", # Tool type (shell, python, etc.)
"command": "string", # Command to execute
"parameters": [dict] # Tool parameters
}
],
"capabilities": ["string"], # List of capabilities
"required_integrations": ["string"], # Required integrations
"configuration": dict, # Skill configuration
"enabled": bool, # Whether skill is enabled
"created_at": "string", # Creation timestamp
"updated_at": "string" # Last update timestamp
}
Validation Result Object Structure
Copy
Ask AI
{
"valid": bool, # Whether configuration is valid
"errors": ["string"], # List of validation errors
"warnings": ["string"], # List of validation warnings
"validated_config": dict # Validated configuration
}