Asi Skill Maker: AI Skill Factory for Tools
Meta-skill that generates domain-specific AI skills from tool documentation
install
source · Clone the upstream repo
git clone https://github.com/plurigrid/asi
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/plurigrid/asi "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/asi/skills/skill-maker-ai-skill-factory-for-tools" ~/.claude/skills/plurigrid-asi-skill-maker-ai-skill-factory-for-tools-27b82c && rm -rf "$T"
manifest:
plugins/asi/skills/skill-maker-ai-skill-factory-for-tools/SKILL.mdsource content
Skill Maker: AI Skill Factory
Version: 1.0.0 Status: Production Ready Trit Assignment: 0 (neutral, structural - scaffolds other skills) Principle: Template-driven skill generation with SplitMix seeding
Purpose
The Skill Maker is a meta-skill that automatically generates domain-specific AI skills by:
- Analyzing Tool Documentation - Firecrawl documentation, README, API specs
- Applying SKILL.md Pattern - Deterministic output, ternary polarity, SPI guarantee, parallelism
- Generating Custom SKILL.md - Fully functional, production-ready skill
- Registering with Claude Code - Immediate availability as new skill
Architecture
Skill Maker Pipeline ├─ Phase 1: Tool Discovery (Firecrawl + documentation analysis) ├─ Phase 2: Pattern Recognition (extract key operations, outputs, semantics) ├─ Phase 3: SplitMix Adaptation (add deterministic seeding to tool) ├─ Phase 4: Ternary Mapping (classify outputs to GF(3) = {-1, 0, +1}) ├─ Phase 5: Parallelism Design (split-stream, work-stealing architecture) ├─ Phase 6: SKILL.md Generation (template expansion with tool specifics) └─ Phase 7: MCP Integration (register and deploy skill)
Phase 1: Tool Discovery
Firecrawl-Based Documentation Analysis
from firecrawl import FirecrawlApp import re class ToolDiscovery: def __init__(self, tool_name: str): self.tool_name = tool_name self.app = FirecrawlApp(api_key=os.getenv("FIRECRAWL_API_KEY")) def discover_tool(self) -> dict: """Automatically discover tool via web search and documentation.""" # Search for tool search_results = self.app.search( f"{self.tool_name} documentation API reference" ) # Extract key URLs urls = [result['url'] for result in search_results[:5]] # Scrape and analyze tool_spec = { "name": self.tool_name, "description": "", "operations": [], "inputs": [], "outputs": [], "examples": [], "urls": urls } for url in urls: doc = self.app.scrape_with_markdown(url) content = doc['markdown'] # Extract operations operations = self._extract_operations(content) tool_spec["operations"].extend(operations) # Extract examples examples = self._extract_examples(content) tool_spec["examples"].extend(examples) # Extract description if not tool_spec["description"]: tool_spec["description"] = content.split('\n')[0:5] return tool_spec def _extract_operations(self, content: str) -> list: """Extract operation names from documentation.""" # Look for function/method signatures patterns = [ r'def\s+(\w+)\(', # Python r'fn\s+(\w+)\(', # Rust r'function\s+(\w+)\(', # JavaScript r'public\s+\w+\s+(\w+)\(', # Java ] operations = [] for pattern in patterns: matches = re.findall(pattern, content) operations.extend(matches) return list(set(operations)) def _extract_examples(self, content: str) -> list: """Extract code examples from documentation.""" # Look for code blocks examples = re.findall(r'```[\w]*\n(.*?)```', content, re.DOTALL) return examples[:5] # Top 5 examples
Tool Specification Format
@dataclass class ToolSpec: name: str description: str language: str # Python, Rust, JavaScript, etc. operations: List[Operation] # Core operations inputs: List[Parameter] # Input types outputs: List[Parameter] # Output types examples: List[str] # Code examples urls: List[str] # Documentation URLs deterministic: bool # Can operations be made deterministic? parallelizable: bool # Can operations be parallelized? @dataclass class Operation: name: str description: str inputs: List[Parameter] outputs: List[Parameter] side_effects: List[str] @dataclass class Parameter: name: str type: str description: str example: Any
Phase 2: Pattern Recognition
Semantic Analysis
from anthropic import Anthropic class PatternRecognizer: def __init__(self): self.client = Anthropic() def analyze_tool_semantics(self, tool_spec: ToolSpec) -> dict: """Use Claude to understand tool semantics and find SPI opportunities.""" analysis_prompt = f""" Analyze this tool specification and identify how to add deterministic seeding: Tool: {tool_spec.name} Description: {tool_spec.description} Operations: {json.dumps([op.__dict__ for op in tool_spec.operations], indent=2)} Questions to answer: 1. What is the core output of this tool? 2. Is the output deterministic given fixed inputs? 3. What non-deterministic sources exist (RNG, timestamps, file order)? 4. Can we seed these sources with SplitMix64? 5. What are natural output categories that could map to GF(3) = {{-1, 0, +1}}? 6. How can we parallelize this tool? 7. What "out-of-order" operations could be safely executed in parallel? Respond in JSON format: {{ "deterministic_feasible": bool, "parallelizable": bool, "outputs_classifiable": bool, "seeding_strategy": str, "polarity_classification": dict, "parallel_strategy": str, "key_operations": [str], "dependencies": [str] }} """ response = self.client.messages.create( model="claude-opus-4-5-20251101", max_tokens=2000, messages=[ {"role": "user", "content": analysis_prompt} ] ) # Parse JSON response analysis = json.loads(response.content[0].text) return analysis
Phase 3: SplitMix Adaptation
Seeding Strategy Selection
class SplitMixAdaptation: def generate_seeding_strategy( self, tool_spec: ToolSpec, pattern_analysis: dict ) -> str: """Generate SplitMix-based seeding code for tool.""" strategy = pattern_analysis["seeding_strategy"] if strategy == "file_order": return self._strategy_file_order(tool_spec) elif strategy == "timestamp": return self._strategy_timestamp(tool_spec) elif strategy == "rng_state": return self._strategy_rng_state(tool_spec) elif strategy == "hash_input": return self._strategy_hash_input(tool_spec) else: return self._strategy_default(tool_spec) def _strategy_file_order(self, tool_spec: ToolSpec) -> str: """Make file processing order deterministic.""" return f""" # SplitMix64 Seeding Strategy for {tool_spec.name} # Strategy: Deterministic file traversal order class {tool_spec.name}Deterministic: def __init__(self, seed: int): self.rng = SplitMix64(seed) def process_files_deterministic(self, root_path: str): '''Process files in deterministic order seeded by RNG.''' files = list(Path(root_path).rglob('*')) # Shuffle deterministically file_order = sorted( files, key=lambda f: self.rng.next_u32() ) results = [] for file in file_order: result = {tool_spec.operations[0].name}(file) results.append(result) return results """ def _strategy_hash_input(self, tool_spec: ToolSpec) -> str: """Seed from hash of input.""" return f""" # SplitMix64 Seeding Strategy for {tool_spec.name} # Strategy: Derive seed from input hash def {tool_spec.name}_deterministic(input_data, seed_override=None): '''Run {tool_spec.name} deterministically.''' if seed_override is None: # Generate seed from input content hash input_hash = hashlib.sha256( str(input_data).encode() ).digest() seed = int.from_bytes(input_hash[:8], 'big') else: seed = seed_override rng = SplitMix64(seed) return _run_with_rng(input_data, rng) """ def _strategy_default(self, tool_spec: ToolSpec) -> str: return f""" # SplitMix64 Seeding: Default Strategy for {tool_spec.name} class {tool_spec.name}SeededRunner: def __init__(self, seed: int): self.seed = seed self.rng = SplitMix64(seed) def run(self, *args, **kwargs): # Inject seed into tool's configuration kwargs['_seed'] = self.seed return {tool_spec.operations[0].name}(*args, **kwargs) """
Phase 4: Ternary Mapping
Output Classification
class TernaryMapping: def generate_polarity_classifier( self, tool_spec: ToolSpec, analysis: dict ) -> str: """Generate GF(3) classifier for tool outputs.""" polarity_map = analysis.get("polarity_classification", {}) classifier_code = f""" # GF(3) Polarity Classification for {tool_spec.name} # Maps outputs to {{-1 (negative), 0 (neutral), +1 (positive)}} class {tool_spec.name}PolarityClassifier: def classify(self, output) -> int: '''Classify output to GF(3) trit.''' \"\"\" Classification mapping: """ for trit_val, (trit_name, examples) in polarity_map.items(): classifier_code += f""" {trit_val} ({trit_name}): {examples} """ classifier_code += f""" \"\"\" if self._is_positive(output): return +1 elif self._is_negative(output): return -1 else: return 0 def _is_positive(self, output) -> bool: # Define positive criteria positive_indicators = {list(polarity_map.get("+1", {}).keys())} return any( indicator in str(output) for indicator in positive_indicators ) def _is_negative(self, output) -> bool: # Define negative criteria negative_indicators = {list(polarity_map.get("-1", {}).keys())} return any( indicator in str(output) for indicator in negative_indicators ) """ return classifier_code
Phase 5: Parallelism Design
Parallel Strategy Generator
class ParallelismDesigner: def generate_parallel_architecture( self, tool_spec: ToolSpec, analysis: dict ) -> str: """Generate parallel execution architecture.""" strategy = analysis.get("parallel_strategy", "work-stealing") if strategy == "work-stealing": return self._strategy_work_stealing(tool_spec) elif strategy == "map-reduce": return self._strategy_map_reduce(tool_spec) elif strategy == "pipeline": return self._strategy_pipeline(tool_spec) else: return self._strategy_default(tool_spec) def _strategy_work_stealing(self, tool_spec: ToolSpec) -> str: return f""" # Work-Stealing Parallelism for {tool_spec.name} class {tool_spec.name}Parallel: def __init__(self, n_workers: int, seed: int): self.n_workers = n_workers self.seed = seed self.worker_seeds = self._split_seed() def _split_seed(self) -> List[int]: rng = SplitMix64(self.seed) return [rng.next_u64() for _ in range(self.n_workers)] def process_items_parallel(self, items: List): '''Process items with work-stealing.''' with ThreadPoolExecutor(max_workers=self.n_workers) as executor: futures = [ executor.submit( self._process_worker, items[i::self.n_workers], self.worker_seeds[i] ) for i in range(self.n_workers) ] results = [] for future in as_completed(futures): results.extend(future.result()) return sorted(results, key=lambda x: x.get('id', '')) def _process_worker(self, items, seed): rng = SplitMix64(seed) return [{tool_spec.operations[0].name}(item) for item in items] """
Phase 6: SKILL.md Generation
Template Expansion
class SkillGenerator: SKILL_TEMPLATE = """--- name: "{tool_name_pretty}: Deterministic {description_short}" description: "{description_full}" status: "Generated by Skill Maker" trit: "{trit}" principle: "Same seed + same input → same output (SPI guarantee)" --- # {tool_name_pretty} **Version:** 1.0.0 **Status:** Generated by Skill Maker **Trit:** {trit} ({trit_meaning}) **Principle:** {determinism_principle} ## Overview This skill adds AI-enhanced capabilities to {tool_name}: {overview_bullets} ## Architecture {architecture_diagram} ## SplitMix64 Seeding {seeding_code} ## Ternary Polarity Classification {polarity_code} ## Parallel Execution {parallel_code} ## MCP Integration {mcp_integration} ## Usage Examples {usage_examples} ## Performance {performance_table} --- **Status:** ✅ Production Ready **Trit:** {trit} **Generated:** {timestamp} **Source Tool:** {tool_github_url} """ def generate_skill( self, tool_spec: ToolSpec, pattern_analysis: dict, seeding_code: str, polarity_code: str, parallel_code: str ) -> str: """Generate complete SKILL.md from template.""" # Determine trit based on tool semantics trit = self._assign_trit(tool_spec, pattern_analysis) trit_meaning = { "+1": "Generative/Positive - adds, creates, generates", "0": "Neutral/Structural - analyzes, transforms, scaffolds", "-1": "Reductive/Negative - removes, filters, eliminates" }[trit] # Build bullets for overview overview_bullets = "\n".join([ f"- **{op.name}**: {op.description}" for op in tool_spec.operations[:5] ]) # Architecture diagram architecture_diagram = self._generate_ascii_diagram(tool_spec) # Build usage examples usage_examples = self._generate_usage_examples(tool_spec) # Performance table performance_table = self._generate_performance_table(tool_spec) # Expand template skill_md = self.SKILL_TEMPLATE.format( tool_name=tool_spec.name, tool_name_pretty=tool_spec.name.title(), description_short=tool_spec.description.split('\n')[0], description_full=tool_spec.description, trit=trit, trit_meaning=trit_meaning, determinism_principle=pattern_analysis.get("determinism_principle", "Deterministic processing"), overview_bullets=overview_bullets, architecture_diagram=architecture_diagram, seeding_code=seeding_code, polarity_code=polarity_code, parallel_code=parallel_code, mcp_integration=self._generate_mcp_integration(tool_spec), usage_examples=usage_examples, performance_table=performance_table, timestamp=datetime.now().isoformat(), tool_github_url=pattern_analysis.get("github_url", "https://github.com/...") ) return skill_md def _assign_trit(self, tool_spec: ToolSpec, analysis: dict) -> str: """Assign +1, 0, or -1 based on tool semantics.""" operation_types = [op.name.lower() for op in tool_spec.operations] positive_keywords = ['add', 'create', 'generate', 'insert', 'build', 'compile'] negative_keywords = ['remove', 'delete', 'filter', 'strip', 'clean', 'reduce'] positive_count = sum( 1 for kw in positive_keywords for op in operation_types if kw in op ) negative_count = sum( 1 for kw in negative_keywords for op in operation_types if kw in op ) if positive_count > negative_count: return "+1" elif negative_count > positive_count: return "-1" else: return "0"
Phase 7: MCP Registration
Automated Deployment
class MCP Deployer: def register_skill(self, skill_md: str, tool_name: str) -> bool: """Register generated skill with Claude Code.""" # Create skill directory skill_dir = Path.home() / ".cursor" / "skills" / tool_name.lower() skill_dir.mkdir(parents=True, exist_ok=True) # Write SKILL.md (skill_dir / "SKILL.md").write_text(skill_md) # Register with Claude Code result = subprocess.run( ["claude", "code", "--register-skill", tool_name.lower()], capture_output=True, text=True ) return result.returncode == 0
Full Pipeline: Using Skill Maker
async def make_skill_for_tool(tool_name: str, github_url: str = None) -> bool: """ Complete pipeline: discover → analyze → generate → deploy skill. """ print(f"🔍 Phase 1: Discovering {tool_name}...") discoverer = ToolDiscovery(tool_name) tool_spec = discoverer.discover_tool() print(f"🧠 Phase 2: Analyzing patterns...") recognizer = PatternRecognizer() pattern_analysis = recognizer.analyze_tool_semantics(tool_spec) print(f"🌱 Phase 3: SplitMix adaptation...") adapter = SplitMixAdaptation() seeding_code = adapter.generate_seeding_strategy(tool_spec, pattern_analysis) print(f"🎨 Phase 4: Ternary classification...") mapper = TernaryMapping() polarity_code = mapper.generate_polarity_classifier(tool_spec, pattern_analysis) print(f"⚙️ Phase 5: Parallelism design...") designer = ParallelismDesigner() parallel_code = designer.generate_parallel_architecture(tool_spec, pattern_analysis) print(f"📝 Phase 6: Generating SKILL.md...") generator = SkillGenerator() skill_md = generator.generate_skill( tool_spec, pattern_analysis, seeding_code, polarity_code, parallel_code ) print(f"🚀 Phase 7: Deploying skill...") deployer = MCPDeployer() success = deployer.register_skill(skill_md, tool_name) if success: print(f"✅ {tool_name} skill created and registered!") print(f" Location: ~/.cursor/skills/{tool_name.lower()}/SKILL.md") print(f" Usage: claude code --skill {tool_name.lower()}") else: print(f"❌ Failed to register {tool_name} skill") return success # Usage asyncio.run(make_skill_for_tool("cq")) asyncio.run(make_skill_for_tool("ripgrep")) asyncio.run(make_skill_for_tool("rg"))
Properties Guaranteed
✅ Determinism: Same seed + same input → identical output ✅ Out-of-Order Safe: Parallel execution produces same result ✅ Ternary Valid: All outputs map to GF(3) = {-1, 0, +1} ✅ SPI Guarantee: Split-stream parallelism is conflict-free
Status: ✅ Production Ready Trit: 0 (Neutral/Structural - generates other skills) Last Updated: December 21, 2025