Skip to main content
Glama
skills_loader.py6.61 kB
"""Universal Skills System for Black Orchid Portable, reusable collaboration modes that work across all projects. Skills are markdown files that define system prompts for different working modes. """ from pathlib import Path from typing import Dict, List, Optional import os def _get_base_dir() -> Path: """Get Black Orchid base directory""" # This file is in modules/, so parent is base directory return Path(__file__).parent.parent def _get_skills_directories() -> List[Path]: """Get list of valid skills directories (public and private)""" base_dir = _get_base_dir() dirs = [] # Public skills directory public_skills = base_dir / "modules" / "skills" if public_skills.exists(): dirs.append(public_skills) # Private skills directory private_skills = base_dir / "private" / "skills" if private_skills.exists(): dirs.append(private_skills) return dirs def _extract_description(content: str) -> Optional[str]: """Extract description from skill file (first heading or paragraph)""" lines = content.strip().split('\n') for line in lines: line = line.strip() # Skip empty lines if not line: continue # First heading if line.startswith('#'): return line.lstrip('#').strip() # First paragraph if len(line) > 20: # Meaningful content return line[:100] + '...' if len(line) > 100 else line return None def list_skills() -> Dict[str, any]: """List all available skills from both public and private directories Returns: Dict with skills list, each containing: - name: skill name (filename without .md) - description: extracted from file content - source: 'public' or 'private' - path: full path to skill file Example: >>> skills = list_skills() >>> for skill in skills['skills']: ... print(f"{skill['name']}: {skill['description']}") """ skills = [] for skills_dir in _get_skills_directories(): source = 'private' if 'private' in str(skills_dir) else 'public' # Find all .md files in directory for skill_file in skills_dir.glob('*.md'): try: # Read file to extract description with open(skill_file, 'r', encoding='utf-8') as f: content = f.read() description = _extract_description(content) skills.append({ 'name': skill_file.stem, # filename without .md 'description': description, 'source': source, 'path': str(skill_file) }) except Exception as e: # If we can't read a file, skip it but don't fail continue return { 'skills': skills, 'count': len(skills), 'message': f"Found {len(skills)} skills" } def use_skill(skill_name: str) -> Dict[str, any]: """Load a skill for the current Claude instance to embody Returns the full skill prompt so Claude can shift into that mode in the current session. Args: skill_name: Name of the skill (filename without .md) Returns: Dict with: - skill_name: name of the skill - prompt: full skill content to embody - source: where the skill came from - instructions: how to use this Example: >>> result = use_skill("reflection") >>> # Claude receives the prompt and shifts into reflection mode """ # Search for skill in all directories for skills_dir in _get_skills_directories(): skill_file = skills_dir / f"{skill_name}.md" if skill_file.exists(): try: with open(skill_file, 'r', encoding='utf-8') as f: prompt = f.read() source = 'private' if 'private' in str(skills_dir) else 'public' return { 'skill_name': skill_name, 'prompt': prompt, 'source': source, 'instructions': ( "This is your skill prompt. Embody this mode in the current session. " "The prompt defines how you should think, communicate, and collaborate " "while in this mode." ) } except Exception as e: return { 'error': f"Failed to load skill '{skill_name}': {str(e)}", 'skill_name': skill_name } # Skill not found available = list_skills() available_names = [s['name'] for s in available['skills']] return { 'error': f"Skill '{skill_name}' not found", 'skill_name': skill_name, 'available_skills': available_names, 'suggestion': f"Use list_skills() to see all available skills" } def spawn_subagent_with_skill(skill_name: str, task: str) -> str: """Spawn a specialized agent with a skill as their system prompt NOTE: This function returns instructions for spawning the agent. Claude must use the Task tool with subagent_type='general-purpose' and inject the skill prompt to actually spawn the agent. Args: skill_name: Name of the skill to use as agent's system context task: What you want the skilled agent to do Returns: Instructions for spawning the agent with the skill Example: >>> instructions = spawn_subagent_with_skill("code-review", "Review auth.py") >>> # Claude will use Task tool to spawn agent with skill prompt """ # First, load the skill skill_result = use_skill(skill_name) if 'error' in skill_result: return f"Cannot spawn agent: {skill_result['error']}" skill_prompt = skill_result['prompt'] # Return instructions for Claude to spawn the agent instructions = f""" To spawn a specialized agent with the '{skill_name}' skill: 1. Use the Task tool with: - subagent_type: 'general-purpose' - description: Short description of the task - prompt: Combine the skill prompt below with your specific task **Skill Prompt for '{skill_name}':** {skill_prompt} **Your Task:** {task} **Suggested Agent Prompt:** You are a Claude instance operating in '{skill_name}' mode. {skill_prompt} Your specific task for this session: {task} Please proceed with this task while maintaining the principles and approach defined in your skill mode. """ return instructions.strip()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/AJ-Gonzalez/black-orchid'

If you have feedback or need assistance with the MCP directory API, please join our Discord server