diff --git a/source/meta-skill-generator/SKILL.md b/source/meta-skill-generator/SKILL.md new file mode 100644 index 0000000..f247a2e --- /dev/null +++ b/source/meta-skill-generator/SKILL.md @@ -0,0 +1,278 @@ +--- +name: meta-skill-generator +description: Creates Claude Code skills with intelligent separation of deterministic operations into Go scripts. Use when users want to create a new skill or improve an existing skill by identifying repetitive code patterns that should be extracted into compiled Go scripts for performance and reliability. Analyzes workflows to determine what requires agent interaction versus what can be pre-compiled into efficient Go binaries. +--- + +# Meta Skill Generator + +## Overview + +This skill generates high-quality Claude Code skills with intelligent workflow analysis. It identifies deterministic operations that don't require agent interaction and generates efficient Go scripts for them, while preserving dynamic agent-based workflows for tasks requiring reasoning and adaptation. + +## Workflow + +Creating a skill follows these steps: + +1. **Understanding phase**: Gather concrete examples and use cases +2. **Analysis phase**: Identify deterministic vs dynamic operations +3. **Planning phase**: Design skill structure with appropriate degrees of freedom +4. **Implementation phase**: Generate Go scripts, Python utilities, and SKILL.md +5. **Testing phase**: Validate scripts and skill structure +6. **Packaging phase**: Create distributable .skill file + +## Step 1: Understanding the Skill with Concrete Examples + +Begin by gathering concrete examples of how the skill will be used. Ask targeted questions: + +- What specific tasks should this skill handle? +- Can you provide 3-5 example user requests? +- What would trigger this skill? +- Are there existing workflows or tools this should integrate with? + +**Example questions for an image-processing skill:** +- "What image operations do you need? Resizing, format conversion, filtering?" +- "Can you show me an example image and what you'd want to do with it?" +- "How would you phrase a request to use this skill?" + +Conclude when you have clear use cases and triggering patterns. + +## Step 2: Analyze for Deterministic vs Dynamic Operations + +For each concrete example, categorize operations: + +**Deterministic operations** (candidates for Go scripts): +- File format conversions (PDF → images, DOCX → text) +- Data transformations with fixed logic (CSV parsing, JSON manipulation) +- Batch operations on multiple files +- Validation checks with clear pass/fail criteria +- Template-based generation with fixed structure +- Mathematical computations +- File system operations (copying, organizing, renaming) + +**Dynamic operations** (keep as agent workflows): +- Content analysis requiring understanding (sentiment, summarization) +- Decision-making based on context +- Creative generation (writing, design suggestions) +- Interactive troubleshooting +- Adapting to unexpected inputs +- Multi-step reasoning chains + +**Indicators for Go script extraction:** +1. Same code pattern rewritten >3 times +2. Performance-critical operations (large files, many iterations) +3. Binary/low-level data manipulation +4. Zero decision-making required +5. Clear input/output contract + +## Step 3: Plan Skill Structure + +Design the skill's organization based on complexity: + +**Simple skills** (1-3 operations): +- SKILL.md with direct instructions +- 1-3 Go scripts in `scripts/` +- Optional: single reference file + +**Medium skills** (4-10 operations): +- SKILL.md with workflow decision tree +- Multiple Go scripts organized by function +- References for detailed documentation +- Optional: assets for templates + +**Complex skills** (10+ operations): +- SKILL.md with high-level workflow +- Multiple reference files by category +- Go scripts organized in subdirectories +- Assets for templates and examples +- Consider: Go package with multiple binaries + +### Degrees of Freedom + +Match specificity to task fragility: + +**High freedom** (natural language instructions): +```markdown +Analyze the document and identify key themes, then structure your +findings based on what you discover. +``` + +**Medium freedom** (parameterized scripts): +```markdown +Run: ./scripts/analyze --format=json --depth=2 input.txt +Interpret the results and determine next steps. +``` + +**Low freedom** (specific scripts, fixed sequence): +```markdown +1. Run: ./scripts/extract_fields input.pdf > fields.json +2. Run: ./scripts/validate_fields fields.json +3. If validation passes, run: ./scripts/fill_form fields.json template.pdf +``` + +## Step 4: Implementation + +### Initialize the Skill + +```bash +python3 /mnt/skills/examples/skill-creator/scripts/init_skill.py --path +``` + +### Generate Go Scripts + +For each deterministic operation identified in Step 2, use `scripts/generate_go_script.py`: + +```bash +scripts/generate_go_script.py \ + --name \ + --description "" \ + --input "" \ + --output "" \ + --logic "" \ + --skill-path +``` + +**Example:** +```bash +scripts/generate_go_script.py \ + --name pdf-to-images \ + --description "Convert PDF pages to PNG images" \ + --input "PDF file path" \ + --output "Directory of PNG files" \ + --logic "Extract each page as separate image, 300 DPI" \ + --skill-path ./my-pdf-skill +``` + +The script will: +1. Generate efficient Go code with proper error handling +2. Include CLI argument parsing +3. Add progress reporting for long operations +4. Create binary in `scripts/bin/` +5. Update SKILL.md with usage instructions + +### Python Utilities + +For operations requiring Python libraries (data science, ML, complex APIs), create Python scripts instead. Use Go for performance-critical, low-level operations. + +### Write SKILL.md + +Follow the skill-creator patterns: + +**Frontmatter:** +```yaml +--- +name: skill-name +description: Comprehensive description including WHAT it does and WHEN to use it. Mention specific triggers: file types, keywords, task patterns. +--- +``` + +**Body structure:** +1. Overview (1-2 sentences) +2. Workflow or Quick Start +3. Detailed sections for each major capability +4. Reference to scripts with clear usage examples +5. Troubleshooting (if applicable) + +**Writing style:** +- Imperative/infinitive form ("Extract text" not "Extracts text") +- Concise - every word must justify its token cost +- Examples over explanations +- Reference bundled resources clearly + +### Reference Files + +Create reference files for: +- API documentation +- Complex workflows (>10 steps) +- Domain knowledge (schemas, specifications) +- Large examples (>100 lines) + +Keep SKILL.md lean by moving detailed content to references: + +```markdown +## Advanced Features + +For form field extraction, see [references/form-fields.md](references/form-fields.md) +For batch processing patterns, see [references/batch-operations.md](references/batch-operations.md) +``` + +### Assets + +Include files to be used in output: +- Templates (.pptx, .docx, .html) +- Images (logos, icons) +- Boilerplate code (starter projects) +- Fonts, stylesheets + +## Step 5: Testing + +Test each Go script: + +```bash +cd scripts/bin +./script-name --help # Verify CLI works +./script-name test-input.txt # Test with real data +./script-name invalid-input # Test error handling +``` + +Test Python scripts: + +```bash +cd scripts +python3 script-name.py test-input +``` + +Verify SKILL.md: +- All script references are accurate +- Examples run successfully +- No broken links to references/assets + +## Step 6: Package the Skill + +```bash +python3 /mnt/skills/examples/skill-creator/scripts/package_skill.py +``` + +This automatically validates: +- YAML frontmatter completeness +- Naming conventions +- File organization +- Script executability + +Fix any validation errors and repackage. + +## Go Script Best Practices + +**Performance:** +- Use goroutines for parallel operations +- Stream large files instead of loading into memory +- Buffer I/O operations + +**Error handling:** +- Return descriptive error messages +- Use exit codes (0=success, 1=error, 2=invalid input) +- Validate inputs before processing + +**CLI design:** +- Support `--help` flag +- Use standard flags package +- Accept input from stdin or file +- Write output to stdout or file + +**Logging:** +- Progress indicators for long operations +- Verbose mode for debugging (`--verbose` flag) +- Errors to stderr, output to stdout + +## Resources + +### scripts/ +- `generate_go_script.py`: Generate Go scripts from specifications +- `test_skill_scripts.py`: Automated testing for all scripts +- `init_skill_with_analysis.py`: End-to-end skill creation with workflow analysis + +### references/ +- `go-patterns.md`: Common Go patterns for skill scripts +- `workflow-analysis.md`: Detailed guide for identifying deterministic operations +- `skill-examples.md`: Real-world examples of well-structured skills + +Run `scripts/generate_go_script.py --help` for detailed usage. diff --git a/source/meta-skill-generator/references/go-patterns.md b/source/meta-skill-generator/references/go-patterns.md new file mode 100644 index 0000000..5b6582f --- /dev/null +++ b/source/meta-skill-generator/references/go-patterns.md @@ -0,0 +1,443 @@ +# Go Patterns for Skill Scripts + +This reference provides battle-tested Go patterns for common operations in Claude Code skills. + +## File Processing Patterns + +### Reading Files Line by Line + +```go +func processFileLineByLine(filename string) error { + file, err := os.Open(filename) + if err != nil { + return fmt.Errorf("failed to open file: %w", err) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + lineNum := 0 + + for scanner.Scan() { + lineNum++ + line := scanner.Text() + + // Process line + if err := processLine(line); err != nil { + return fmt.Errorf("error on line %d: %w", lineNum, err) + } + } + + if err := scanner.Err(); err != nil { + return fmt.Errorf("scanner error: %w", err) + } + + return nil +} +``` + +### Streaming Large Files + +```go +func streamProcess(input, output string) error { + inFile, err := os.Open(input) + if err != nil { + return err + } + defer inFile.Close() + + outFile, err := os.Create(output) + if err != nil { + return err + } + defer outFile.Close() + + reader := bufio.NewReader(inFile) + writer := bufio.NewWriter(outFile) + defer writer.Flush() + + buf := make([]byte, 4096) + for { + n, err := reader.Read(buf) + if err != nil && err != io.EOF { + return err + } + if n == 0 { + break + } + + // Process chunk + processed := processChunk(buf[:n]) + + if _, err := writer.Write(processed); err != nil { + return err + } + } + + return nil +} +``` + +## Concurrent Processing Patterns + +### Worker Pool + +```go +func processParallel(items []string, workers int) error { + jobs := make(chan string, len(items)) + results := make(chan error, len(items)) + + // Start workers + var wg sync.WaitGroup + for i := 0; i < workers; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for item := range jobs { + if err := processItem(item); err != nil { + results <- err + } else { + results <- nil + } + } + }() + } + + // Send jobs + for _, item := range items { + jobs <- item + } + close(jobs) + + // Wait for completion + wg.Wait() + close(results) + + // Check for errors + for err := range results { + if err != nil { + return err + } + } + + return nil +} +``` + +### Rate Limited Processing + +```go +func processWithRateLimit(items []string, requestsPerSecond int) error { + limiter := time.NewTicker(time.Second / time.Duration(requestsPerSecond)) + defer limiter.Stop() + + for i, item := range items { + <-limiter.C + + if *verbose { + log.Printf("Processing %d/%d: %s", i+1, len(items), item) + } + + if err := processItem(item); err != nil { + return fmt.Errorf("failed to process %s: %w", item, err) + } + } + + return nil +} +``` + +## Progress Reporting + +### Simple Progress Bar + +```go +func showProgress(current, total int) { + if total == 0 { + return + } + + percent := float64(current) / float64(total) * 100 + filled := int(percent / 2) // 50 chars max + + fmt.Fprintf(os.Stderr, "\r[") + for i := 0; i < 50; i++ { + if i < filled { + fmt.Fprintf(os.Stderr, "=") + } else { + fmt.Fprintf(os.Stderr, " ") + } + } + fmt.Fprintf(os.Stderr, "] %.1f%% (%d/%d)", percent, current, total) + + if current == total { + fmt.Fprintln(os.Stderr) + } +} +``` + +### Timed Progress Updates + +```go +type ProgressTracker struct { + total int + current int + lastUpdate time.Time + updateEvery time.Duration +} + +func NewProgressTracker(total int) *ProgressTracker { + return &ProgressTracker{ + total: total, + updateEvery: 500 * time.Millisecond, + lastUpdate: time.Now(), + } +} + +func (p *ProgressTracker) Update(current int) { + p.current = current + + if time.Since(p.lastUpdate) < p.updateEvery && current < p.total { + return + } + + p.lastUpdate = time.Now() + showProgress(p.current, p.total) +} +``` + +## Error Handling Patterns + +### Recoverable vs Fatal Errors + +```go +type ProcessResult struct { + Processed int + Failed int + Errors []error +} + +func processWithRecovery(items []string) (*ProcessResult, error) { + result := &ProcessResult{} + + for _, item := range items { + if err := processItem(item); err != nil { + // Check if error is recoverable + if isRecoverable(err) { + result.Failed++ + result.Errors = append(result.Errors, + fmt.Errorf("%s: %w", item, err)) + continue + } else { + // Fatal error + return result, fmt.Errorf("fatal error processing %s: %w", item, err) + } + } + result.Processed++ + } + + return result, nil +} + +func isRecoverable(err error) bool { + // Define what errors are recoverable + return errors.Is(err, os.ErrNotExist) || + errors.Is(err, os.ErrPermission) +} +``` + +## CLI Patterns + +### Multiple Input Sources + +```go +func getInput() (io.Reader, func() error, error) { + if flag.NArg() > 0 { + // File input + filename := flag.Arg(0) + file, err := os.Open(filename) + if err != nil { + return nil, nil, err + } + return file, file.Close, nil + } else { + // Stdin input + return os.Stdin, func() error { return nil }, nil + } +} + +func main() { + // ... flag parsing ... + + input, cleanup, err := getInput() + if err != nil { + log.Fatal(err) + } + defer cleanup() + + if err := process(input); err != nil { + log.Fatal(err) + } +} +``` + +### Configuration with Defaults + +```go +type Config struct { + Workers int + BufferSize int + Timeout time.Duration + OutputDir string +} + +func loadConfig() *Config { + cfg := &Config{ + Workers: 4, + BufferSize: 4096, + Timeout: 30 * time.Second, + OutputDir: "output", + } + + flag.IntVar(&cfg.Workers, "workers", cfg.Workers, "Number of worker goroutines") + flag.IntVar(&cfg.BufferSize, "buffer", cfg.BufferSize, "Buffer size in bytes") + flag.DurationVar(&cfg.Timeout, "timeout", cfg.Timeout, "Operation timeout") + flag.StringVar(&cfg.OutputDir, "output", cfg.OutputDir, "Output directory") + + flag.Parse() + + return cfg +} +``` + +## Data Processing Patterns + +### CSV Processing + +```go +func processCSV(filename string) error { + file, err := os.Open(filename) + if err != nil { + return err + } + defer file.Close() + + reader := csv.NewReader(file) + reader.TrimLeadingSpace = true + + // Read header + header, err := reader.Read() + if err != nil { + return fmt.Errorf("failed to read header: %w", err) + } + + // Process rows + for { + record, err := reader.Read() + if err == io.EOF { + break + } + if err != nil { + return fmt.Errorf("failed to read row: %w", err) + } + + // Convert to map for easy access + row := make(map[string]string) + for i, value := range record { + if i < len(header) { + row[header[i]] = value + } + } + + if err := processRow(row); err != nil { + return err + } + } + + return nil +} +``` + +### JSON Streaming + +```go +func processJSONStream(r io.Reader) error { + decoder := json.NewDecoder(r) + + // Expect array of objects + // Read opening bracket + if _, err := decoder.Token(); err != nil { + return err + } + + // Process objects + for decoder.More() { + var obj YourType + if err := decoder.Decode(&obj); err != nil { + return err + } + + if err := processObject(&obj); err != nil { + return err + } + } + + // Read closing bracket + if _, err := decoder.Token(); err != nil { + return err + } + + return nil +} +``` + +## Testing Patterns + +### Table-Driven Tests + +```go +func TestProcess(t *testing.T) { + tests := []struct { + name string + input string + want string + wantErr bool + }{ + { + name: "valid input", + input: "test.txt", + want: "output.txt", + }, + { + name: "invalid input", + input: "nonexistent.txt", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := process(tt.input) + if (err != nil) != tt.wantErr { + t.Errorf("process() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("process() = %v, want %v", got, tt.want) + } + }) + } +} +``` + +## Best Practices Summary + +1. **Always handle errors explicitly** - Never ignore errors +2. **Close resources** - Use defer for cleanup +3. **Validate inputs early** - Fail fast with clear messages +4. **Use buffered I/O** - For file operations +5. **Progress feedback** - For long operations +6. **Graceful degradation** - Separate recoverable from fatal errors +7. **Configurable behavior** - Use flags for common parameters +8. **Stream large data** - Don't load entire files into memory +9. **Parallel processing** - Use goroutines for independent operations +10. **Test thoroughly** - Use table-driven tests diff --git a/source/meta-skill-generator/references/skill-examples.md b/source/meta-skill-generator/references/skill-examples.md new file mode 100644 index 0000000..fb4ac32 --- /dev/null +++ b/source/meta-skill-generator/references/skill-examples.md @@ -0,0 +1,334 @@ +# Skill Examples + +Real-world examples of well-structured skills with Go scripts and agent workflows. + +## Example 1: PDF Tools Skill + +### Structure +``` +pdf-tools/ +├── SKILL.md +├── scripts/ +│ ├── pdf-to-images.go +│ ├── merge-pdfs.go +│ ├── extract-text.go +│ ├── rotate-pages.go +│ └── bin/ +│ ├── pdf-to-images +│ ├── merge-pdfs +│ ├── extract-text +│ └── rotate-pages +└── references/ + └── pdf-formats.md +``` + +### SKILL.md Excerpt +```markdown +--- +name: pdf-tools +description: Comprehensive PDF manipulation toolkit. Use when users need to convert, merge, split, rotate, or extract content from PDF files. Triggers: mentions of PDF, .pdf files uploaded, requests for document manipulation. +--- + +# PDF Tools + +Tools for efficient PDF manipulation with compiled binaries for performance. + +## Quick Start + +Common operations: + +**Extract text:** +```bash +scripts/bin/extract-text document.pdf +``` + +**Convert to images:** +```bash +scripts/bin/pdf-to-images document.pdf output/ +``` + +**Merge multiple PDFs:** +```bash +scripts/bin/merge-pdfs file1.pdf file2.pdf file3.pdf output.pdf +``` + +## Workflow Decision Tree + +1. **Simple operations** (extract, convert, merge, rotate) + → Use appropriate Go script from scripts/bin/ + +2. **Content analysis** (summarize, find information) + → First extract text, then analyze content + +3. **Form filling** + → See references/pdf-forms.md for detailed workflow +``` + +### When to Use What + +- **Go scripts:** All standard PDF operations (deterministic) +- **Agent workflow:** Content analysis, recommendations +- **References:** Complex topics like form handling + +## Example 2: Data Processing Skill + +### Structure +``` +data-processor/ +├── SKILL.md +├── scripts/ +│ ├── csv-to-json.go +│ ├── json-to-csv.go +│ ├── validate-schema.go +│ ├── analyze_data.py (Python for pandas) +│ └── bin/ +│ ├── csv-to-json +│ ├── json-to-csv +│ └── validate-schema +└── references/ + ├── schemas.md + └── analysis-patterns.md +``` + +### SKILL.md Excerpt +```markdown +--- +name: data-processor +description: Convert and analyze structured data formats. Use for CSV, JSON, XML conversions, data validation, and exploratory analysis. Triggers: data files uploaded, mentions of CSV/JSON/XML, requests for data analysis or conversion. +--- + +# Data Processor + +## Operations + +### Format Conversions (Go Scripts) + +Fast, deterministic conversions: + +```bash +# CSV to JSON +scripts/bin/csv-to-json input.csv output.json + +# JSON to CSV +scripts/bin/json-to-csv input.json output.csv + +# Validate against schema +scripts/bin/validate-schema data.json schema.json +``` + +### Data Analysis (Python + Agent) + +1. Run initial analysis: +```bash +python3 scripts/analyze_data.py data.csv +``` + +2. Interpret results and provide insights: + - Identify patterns + - Suggest visualizations + - Recommend next steps +``` + +### Pattern: Two-Phase Processing + +This skill demonstrates the common pattern: + +**Phase 1: Go Scripts** +- Fast data transformation +- Schema validation +- Format conversion +- Output: structured data + +**Phase 2: Agent Workflow** +- Interpret results +- Find insights +- Make recommendations +- Output: human-readable analysis + +## Example 3: Image Tools Skill + +### Structure +``` +image-tools/ +├── SKILL.md +├── scripts/ +│ ├── resize-image.go +│ ├── convert-format.go +│ ├── batch-process.go +│ └── bin/ +│ ├── resize-image +│ ├── convert-format +│ └── batch-process +└── assets/ + └── watermark.png +``` + +### SKILL.md Excerpt +```markdown +--- +name: image-tools +description: Image manipulation and batch processing. Use for resizing, format conversion, cropping, rotating images. Supports batch operations. Triggers: image files uploaded, mentions of image processing, resize, convert, crop, rotate. +--- + +# Image Tools + +## Single Image Operations + +```bash +# Resize +scripts/bin/resize-image input.jpg 800x600 output.jpg + +# Convert format +scripts/bin/convert-format input.jpg output.png + +# Rotate +scripts/bin/rotate-image input.jpg 90 output.jpg +``` + +## Batch Processing + +Process entire directories efficiently: + +```bash +scripts/bin/batch-process \ + --operation resize \ + --size 800x600 \ + --input images/ \ + --output resized/ +``` + +The batch processor uses parallel goroutines for performance. + +## When to Use Agent vs Scripts + +**Use Go scripts for:** +- Standard operations (resize, crop, rotate, convert) +- Batch processing +- Operations with clear parameters + +**Use agent workflow for:** +- "Make this image look better" (subjective) +- "Find the best crop for this portrait" (requires understanding) +- Choosing between multiple processing options +``` + +## Key Patterns Across Examples + +### 1. Clear Separation of Concerns + +**Deterministic → Go scripts** +- Format conversions +- Standard transformations +- Validation +- Batch operations + +**Reasoning required → Agent workflows** +- Content analysis +- Recommendations +- Context-dependent decisions +- Creative tasks + +### 2. Performance Where It Matters + +Use Go for: +- Large file processing +- Batch operations (parallel) +- High-volume tasks +- Binary data manipulation + +### 3. Progressive Disclosure + +**SKILL.md:** High-level workflows and common operations +**References/:** Detailed documentation for complex topics +**Scripts/:** Implementation of deterministic operations + +### 4. User-Friendly CLI + +All Go scripts follow patterns: +- `--help` flag +- Clear error messages +- Progress indicators for long operations +- Verbose mode for debugging + +### 5. Testing Strategy + +Each skill includes: +- Example inputs in README or references +- Test commands for each script +- Expected outputs documented + +## Anti-Example: What Not to Do + +### ❌ Over-Scripting +```markdown +# DON'T: Script everything including one-liners +scripts/bin/list-files # Just use 'ls'! +scripts/bin/copy-file # Just use 'cp'! +``` + +### ❌ Under-Scripting +```markdown +# DON'T: Agent workflow for repeated deterministic tasks + +For each file: +1. Read the file content +2. Convert JSON to YAML +3. Save to new location + +# SHOULD BE: scripts/bin/json-to-yaml (called once for batch) +``` + +### ❌ Wrong Tool +```markdown +# DON'T: Go for data science +scripts/bin/train-ml-model # Use Python! + +# DON'T: Python for file conversion +scripts/convert_csv.py # Use Go for performance! +``` + +## Template for New Skills + +Based on these patterns: + +```markdown +--- +name: my-skill +description: What it does and when to use it. Include specific triggers. +--- + +# My Skill + +## Quick Start + +[Most common operation with example] + +## Operations + +### Category 1: [Deterministic Operations] +[Go script usage examples] + +### Category 2: [Analysis/Reasoning] +[Agent workflow description] + +## Workflow Patterns + +[When to use what] + +## Resources + +[References to scripts, references, assets] +``` + +## Measuring Success + +A well-designed skill has: + +✅ Clear triggering in description +✅ Go scripts for repeated deterministic tasks +✅ Agent workflows for reasoning tasks +✅ Lean SKILL.md (<500 lines) +✅ Detailed references for complex topics +✅ Tested, working scripts +✅ Clear usage examples +✅ No redundant tools (use bash when appropriate) diff --git a/source/meta-skill-generator/references/workflow-analysis.md b/source/meta-skill-generator/references/workflow-analysis.md new file mode 100644 index 0000000..36b6aa7 --- /dev/null +++ b/source/meta-skill-generator/references/workflow-analysis.md @@ -0,0 +1,283 @@ +# Workflow Analysis Guide + +This guide helps identify which operations should be Go scripts vs agent workflows. + +## Decision Framework + +### Ask These Questions + +For each operation in your skill, evaluate: + +1. **Does it require understanding/interpretation?** + - YES → Agent workflow + - NO → Continue + +2. **Is the logic completely deterministic?** + - NO → Agent workflow + - YES → Continue + +3. **Could it benefit from compilation/performance?** + - YES → Go script + - NO → Continue + +4. **Does it need Python libraries?** + - YES → Python script + - NO → Go script + +## Detailed Analysis + +### Strongly Favor Go Scripts For: + +**File operations:** +- Format conversions (PDF→PNG, CSV→JSON) +- Splitting/merging files +- Batch renaming/organizing +- File validation (format checks) +- Compression/decompression + +**Data transformations:** +- Parsing structured data (CSV, JSON, XML) +- Format conversions with fixed rules +- Data validation against schemas +- Mathematical computations +- Text processing with regex + +**Batch operations:** +- Processing thousands of files +- Parallel operations on independent items +- High-volume data processing +- Performance-critical tasks + +**Binary/low-level:** +- Image manipulation (resize, crop, rotate) +- Audio/video processing +- Network protocols +- Cryptographic operations + +### Strongly Favor Agent Workflows For: + +**Content understanding:** +- Sentiment analysis +- Topic extraction +- Summarization +- Question answering +- Semantic search + +**Decision-making:** +- Choosing strategies based on context +- Adapting to unexpected inputs +- Multi-step reasoning +- Evaluating trade-offs + +**Creative tasks:** +- Writing (articles, emails, code comments) +- Design suggestions +- Naming (variables, files, projects) +- Brainstorming + +**Interactive processes:** +- Troubleshooting +- Guided workflows with user input +- Adaptive error handling +- Context-dependent branching + +### Consider Python Scripts For: + +**Data science:** +- Pandas/NumPy operations +- Statistical analysis +- Data visualization +- Machine learning inference + +**Specialized libraries:** +- Computer vision (OpenCV) +- NLP (spaCy, NLTK) +- Web scraping (BeautifulSoup) +- API clients with complex auth + +**Prototyping:** +- Quick experiments +- One-off utilities +- Testing ideas before Go implementation + +## Real-World Examples + +### Example 1: PDF Processing Skill + +**User requests:** +1. "Extract text from this PDF" +2. "Rotate all pages 90 degrees" +3. "Summarize the key points in this PDF" +4. "Split this PDF into separate pages" + +**Analysis:** + +| Request | Operation | Type | Reason | +|---------|-----------|------|--------| +| Extract text | pdf-extract-text | Go script | Deterministic, parsing | +| Rotate pages | pdf-rotate-pages | Go script | Deterministic, binary | +| Summarize | summarize-document | Agent workflow | Understanding required | +| Split pages | pdf-split-pages | Go script | Deterministic, file ops | + +**Go scripts:** 3 +**Agent workflows:** 1 + +### Example 2: Data Analysis Skill + +**User requests:** +1. "Convert this CSV to JSON" +2. "Find outliers in this dataset" +3. "Plot the trends in this data" +4. "What insights can you find?" + +**Analysis:** + +| Request | Operation | Type | Reason | +|---------|-----------|------|--------| +| CSV to JSON | csv-to-json | Go script | Simple conversion | +| Find outliers | find-outliers | Python script | Statistical libraries | +| Plot trends | plot-data | Python script | Matplotlib/Seaborn | +| Find insights | analyze-insights | Agent workflow | Interpretation needed | + +**Go scripts:** 1 +**Python scripts:** 2 +**Agent workflows:** 1 + +### Example 3: Code Generation Skill + +**User requests:** +1. "Format this code" +2. "Generate boilerplate for a REST API" +3. "Review this code for bugs" +4. "Add error handling" + +**Analysis:** + +| Request | Operation | Type | Reason | +|---------|-----------|------|--------| +| Format code | format-code | Go script | Deterministic rules | +| Generate boilerplate | generate-boilerplate | Go script | Template-based | +| Review for bugs | review-code | Agent workflow | Reasoning required | +| Add error handling | add-error-handling | Agent workflow | Context-dependent | + +**Go scripts:** 2 +**Agent workflows:** 2 + +## Common Patterns + +### Pattern: "Process and Analyze" + +Many skills have this two-phase pattern: + +1. **Process phase** (Go script) + - Extract/transform/validate data + - Fixed, deterministic operations + - Output: structured data + +2. **Analyze phase** (Agent workflow) + - Interpret results + - Make recommendations + - Context-dependent decisions + +**Example:** +```markdown +1. Run: scripts/bin/extract-metrics data.log + Extracts structured metrics to metrics.json + +2. Analyze the metrics and identify: + - Performance bottlenecks + - Unusual patterns + - Recommended optimizations +``` + +### Pattern: "Validate and Act" + +1. **Validate** (Go script) + - Check format/schema + - Fast, deterministic + - Output: valid/invalid + errors + +2. **Act** (Agent workflow or Go script) + - If valid → Go script for fixed action + - If invalid → Agent helps troubleshoot + +**Example:** +```markdown +1. Run: scripts/bin/validate-config config.yaml + - Validates against schema + - Returns validation errors + +2. If valid: + - Run: scripts/bin/apply-config config.yaml + + If invalid: + - Review errors and suggest fixes +``` + +### Pattern: "Batch with Exceptions" + +1. **Batch process** (Go script) + - Process 95% of standard cases + - Fast, parallel + - Flag exceptions + +2. **Handle exceptions** (Agent workflow) + - Review flagged items + - Make case-by-case decisions + - Learn patterns for future + +## Anti-Patterns + +### ❌ Over-Engineering + +Don't create Go scripts for: +- Operations done once +- Simple 5-line operations +- Operations that may need frequent changes + +**Better:** Keep as agent workflow or simple bash command + +### ❌ Under-Engineering + +Don't use agent workflows for: +- Operations rewritten 10+ times +- Performance-critical bottlenecks +- Operations with clear pass/fail criteria + +**Better:** Extract to Go script + +### ❌ Wrong Tool + +Don't use Go for: +- Complex data science (use Python) +- Operations requiring heavyweight libraries +- Rapid prototyping + +Don't use Python for: +- High-performance requirements +- Binary/low-level operations +- Simple file processing + +## Optimization Checklist + +When reviewing a skill design: + +- [ ] Every Go script is truly deterministic +- [ ] Every agent workflow truly needs reasoning +- [ ] No operations rewritten 3+ times +- [ ] Performance-critical paths identified +- [ ] Python used only where libraries needed +- [ ] Clear boundaries between phases +- [ ] Error handling strategy defined +- [ ] Testing approach planned + +## Next Steps + +After analysis: + +1. List all Go scripts to create +2. List all Python scripts to create +3. Document agent workflows in SKILL.md +4. Create integration points between scripts and workflows +5. Plan testing strategy +6. Implement in priority order diff --git a/source/meta-skill-generator/scripts/__pycache__/analyze_workflow.cpython-312.pyc b/source/meta-skill-generator/scripts/__pycache__/analyze_workflow.cpython-312.pyc new file mode 100644 index 0000000..f9e89d9 Binary files /dev/null and b/source/meta-skill-generator/scripts/__pycache__/analyze_workflow.cpython-312.pyc differ diff --git a/source/meta-skill-generator/scripts/__pycache__/generate_go_script.cpython-312.pyc b/source/meta-skill-generator/scripts/__pycache__/generate_go_script.cpython-312.pyc new file mode 100644 index 0000000..0ccf771 Binary files /dev/null and b/source/meta-skill-generator/scripts/__pycache__/generate_go_script.cpython-312.pyc differ diff --git a/source/meta-skill-generator/scripts/__pycache__/init_skill_with_analysis.cpython-312.pyc b/source/meta-skill-generator/scripts/__pycache__/init_skill_with_analysis.cpython-312.pyc new file mode 100644 index 0000000..30c87ef Binary files /dev/null and b/source/meta-skill-generator/scripts/__pycache__/init_skill_with_analysis.cpython-312.pyc differ diff --git a/source/meta-skill-generator/scripts/analyze_workflow.py b/source/meta-skill-generator/scripts/analyze_workflow.py new file mode 100755 index 0000000..de2e2d4 --- /dev/null +++ b/source/meta-skill-generator/scripts/analyze_workflow.py @@ -0,0 +1,271 @@ +#!/usr/bin/env python3 +""" +Workflow Analysis Script for Meta Skill Generator + +Analyzes user requirements and suggests which operations should be: +- Go scripts (deterministic, performance-critical) +- Python scripts (library-heavy, data science) +- Agent workflows (requires reasoning, context-dependent) + +Usage: + analyze_workflow.py [--examples file1.txt file2.txt ...] [--interactive] +""" + +import argparse +import sys +from pathlib import Path +from typing import List, Dict, Tuple + +# Keywords that indicate deterministic operations +DETERMINISTIC_KEYWORDS = { + 'convert', 'transform', 'parse', 'extract', 'validate', + 'format', 'encode', 'decode', 'compress', 'decompress', + 'resize', 'crop', 'rotate', 'merge', 'split', + 'sort', 'filter', 'calculate', 'compute' +} + +# Keywords that indicate dynamic/reasoning operations +DYNAMIC_KEYWORDS = { + 'analyze', 'understand', 'interpret', 'decide', 'choose', + 'suggest', 'recommend', 'summarize', 'explain', 'describe', + 'evaluate', 'assess', 'determine', 'identify', 'classify' +} + +# Keywords that suggest Go (performance-critical) +GO_INDICATORS = { + 'large file', 'batch', 'thousands', 'millions', 'concurrent', + 'parallel', 'performance', 'fast', 'binary', 'low-level', + 'file system', 'network', 'stream' +} + +# Keywords that suggest Python (library-heavy) +PYTHON_INDICATORS = { + 'pandas', 'numpy', 'scikit', 'machine learning', 'data science', + 'plot', 'graph', 'visualization', 'api client', 'requests', + 'beautiful soup', 'selenium', 'opencv' +} + +class OperationAnalyzer: + def __init__(self): + self.operations = [] + + def analyze_text(self, text: str) -> List[Dict]: + """Analyze text and identify operations.""" + text_lower = text.lower() + sentences = text.replace('?', '.').replace('!', '.').split('.') + + operations = [] + for sentence in sentences: + sentence = sentence.strip() + if not sentence: + continue + + op = self._analyze_sentence(sentence) + if op: + operations.append(op) + + return operations + + def _analyze_sentence(self, sentence: str) -> Dict: + """Analyze a single sentence for operation type.""" + sentence_lower = sentence.lower() + + # Check for deterministic vs dynamic + det_score = sum(1 for kw in DETERMINISTIC_KEYWORDS if kw in sentence_lower) + dyn_score = sum(1 for kw in DYNAMIC_KEYWORDS if kw in sentence_lower) + + # Check for Go vs Python indicators + go_score = sum(1 for kw in GO_INDICATORS if kw in sentence_lower) + py_score = sum(1 for kw in PYTHON_INDICATORS if kw in sentence_lower) + + if det_score == 0 and dyn_score == 0: + return None + + # Determine operation type + if det_score > dyn_score: + if go_score > py_score: + op_type = 'go_script' + reason = 'Deterministic operation with performance/binary characteristics' + elif py_score > 0: + op_type = 'python_script' + reason = 'Deterministic operation requiring specialized libraries' + else: + op_type = 'go_script' + reason = 'Deterministic operation suitable for compiled binary' + else: + op_type = 'agent_workflow' + reason = 'Requires reasoning, context analysis, or decision-making' + + return { + 'description': sentence, + 'type': op_type, + 'reason': reason, + 'det_score': det_score, + 'dyn_score': dyn_score, + 'go_score': go_score, + 'py_score': py_score + } + + def generate_recommendations(self, operations: List[Dict]) -> str: + """Generate recommendations report.""" + go_ops = [op for op in operations if op['type'] == 'go_script'] + py_ops = [op for op in operations if op['type'] == 'python_script'] + agent_ops = [op for op in operations if op['type'] == 'agent_workflow'] + + report = [] + report.append("=" * 70) + report.append("WORKFLOW ANALYSIS REPORT") + report.append("=" * 70) + report.append("") + + report.append(f"Total operations identified: {len(operations)}") + report.append(f" - Go scripts recommended: {len(go_ops)}") + report.append(f" - Python scripts recommended: {len(py_ops)}") + report.append(f" - Agent workflows recommended: {len(agent_ops)}") + report.append("") + + if go_ops: + report.append("-" * 70) + report.append("GO SCRIPTS (Deterministic, Performance-Critical)") + report.append("-" * 70) + for i, op in enumerate(go_ops, 1): + report.append(f"\n{i}. {op['description']}") + report.append(f" Reason: {op['reason']}") + report.append(f" Suggested name: {self._suggest_script_name(op['description'])}") + report.append("") + + if py_ops: + report.append("-" * 70) + report.append("PYTHON SCRIPTS (Library-Heavy Operations)") + report.append("-" * 70) + for i, op in enumerate(py_ops, 1): + report.append(f"\n{i}. {op['description']}") + report.append(f" Reason: {op['reason']}") + report.append(f" Suggested name: {self._suggest_script_name(op['description'])}") + report.append("") + + if agent_ops: + report.append("-" * 70) + report.append("AGENT WORKFLOWS (Reasoning Required)") + report.append("-" * 70) + for i, op in enumerate(agent_ops, 1): + report.append(f"\n{i}. {op['description']}") + report.append(f" Reason: {op['reason']}") + report.append(f" Implementation: Keep as natural language workflow in SKILL.md") + report.append("") + + report.append("=" * 70) + report.append("RECOMMENDATIONS") + report.append("=" * 70) + report.append("") + + if go_ops: + report.append("For Go scripts:") + report.append(" 1. Use generate_go_script.py to create each script") + report.append(" 2. Focus on performance and error handling") + report.append(" 3. Support parallel processing where applicable") + report.append("") + + if py_ops: + report.append("For Python scripts:") + report.append(" 1. Create scripts in scripts/ directory") + report.append(" 2. Add requirements.txt for dependencies") + report.append(" 3. Consider virtual environments") + report.append("") + + if agent_ops: + report.append("For agent workflows:") + report.append(" 1. Document in SKILL.md with clear decision points") + report.append(" 2. Provide examples for different scenarios") + report.append(" 3. Use references/ for detailed guidance") + report.append("") + + return '\n'.join(report) + + def _suggest_script_name(self, description: str) -> str: + """Suggest a script name from description.""" + # Extract key verbs and nouns + words = description.lower().split() + important_words = [] + + for word in words: + cleaned = ''.join(c for c in word if c.isalnum()) + if cleaned in DETERMINISTIC_KEYWORDS or len(cleaned) > 3: + important_words.append(cleaned) + if len(important_words) >= 3: + break + + return '-'.join(important_words[:3]) if important_words else 'operation' + +def interactive_mode(): + """Run in interactive mode to gather requirements.""" + print("=" * 70) + print("WORKFLOW ANALYSIS - INTERACTIVE MODE") + print("=" * 70) + print("\nDescribe the operations your skill should perform.") + print("Enter each operation on a separate line.") + print("Press Ctrl+D (Unix) or Ctrl+Z (Windows) when done.\n") + + lines = [] + try: + while True: + line = input("> ") + if line.strip(): + lines.append(line) + except EOFError: + pass + + return '\n'.join(lines) + +def main(): + parser = argparse.ArgumentParser( + description='Analyze workflows to identify deterministic vs dynamic operations', + formatter_class=argparse.RawDescriptionHelpFormatter + ) + + parser.add_argument('--examples', nargs='+', help='Files containing example requests') + parser.add_argument('--interactive', action='store_true', help='Run in interactive mode') + parser.add_argument('--output', help='Output file for report (default: stdout)') + + args = parser.parse_args() + + analyzer = OperationAnalyzer() + + # Gather input + text = "" + if args.interactive: + text = interactive_mode() + elif args.examples: + for example_file in args.examples: + path = Path(example_file) + if path.exists(): + text += path.read_text() + '\n' + else: + print(f"Warning: File not found: {example_file}", file=sys.stderr) + else: + print("Error: Provide --examples or use --interactive mode", file=sys.stderr) + sys.exit(1) + + if not text.strip(): + print("Error: No input provided", file=sys.stderr) + sys.exit(1) + + # Analyze + operations = analyzer.analyze_text(text) + + if not operations: + print("No operations detected in input", file=sys.stderr) + sys.exit(1) + + # Generate report + report = analyzer.generate_recommendations(operations) + + # Output + if args.output: + Path(args.output).write_text(report) + print(f"✅ Report written to: {args.output}") + else: + print(report) + +if __name__ == '__main__': + main() diff --git a/source/meta-skill-generator/scripts/generate_go_script.py b/source/meta-skill-generator/scripts/generate_go_script.py new file mode 100755 index 0000000..b629625 --- /dev/null +++ b/source/meta-skill-generator/scripts/generate_go_script.py @@ -0,0 +1,438 @@ +#!/usr/bin/env python3 +""" +Go Script Generator for Claude Code Skills + +Analyzes operation requirements and generates efficient Go scripts for +deterministic operations that don't require agent interaction. + +Usage: + generate_go_script.py --name --description \ + --input --output \ + --logic --skill-path + +Example: + generate_go_script.py \ + --name pdf-to-images \ + --description "Convert PDF pages to PNG images" \ + --input "PDF file path" \ + --output "Directory of PNG files" \ + --logic "Extract each page as separate image at 300 DPI" \ + --skill-path ./my-skill +""" + +import argparse +import sys +from pathlib import Path +from textwrap import dedent + +# Go script template with best practices +GO_SCRIPT_TEMPLATE = '''package main + +import ( + "flag" + "fmt" + "log" + "os" + {extra_imports} +) + +// {description} +// Generated by meta-skill-generator for Claude Code skills + +var ( + verbose = flag.Bool("verbose", false, "Enable verbose logging") + help = flag.Bool("help", false, "Show this help message") +) + +func main() {{ + flag.Usage = usage + flag.Parse() + + if *help {{ + usage() + os.Exit(0) + }} + + if *verbose {{ + log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) + }} else {{ + log.SetFlags(0) + }} + + // Validate command line arguments + if err := validateArgs(); err != nil {{ + fmt.Fprintf(os.Stderr, "Error: %v\\n", err) + usage() + os.Exit(2) + }} + + // Execute main logic + if err := run(); err != nil {{ + fmt.Fprintf(os.Stderr, "Error: %v\\n", err) + os.Exit(1) + }} +}} + +func usage() {{ + fmt.Fprintf(os.Stderr, "Usage: %s [options] {usage_args}\\n", os.Args[0]) + fmt.Fprintf(os.Stderr, "\\n{description}\\n\\n") + fmt.Fprintf(os.Stderr, "Input: {input_desc}\\n") + fmt.Fprintf(os.Stderr, "Output: {output_desc}\\n\\n") + fmt.Fprintf(os.Stderr, "Options:\\n") + flag.PrintDefaults() +}} + +func validateArgs() error {{ + {validation_logic} + return nil +}} + +func run() error {{ + if *verbose {{ + log.Println("Starting {name}...") + }} + + {run_logic} + + if *verbose {{ + log.Println("Completed successfully") + }} + return nil +}} + +{helper_functions} +''' + +def infer_imports(logic_desc): + """Infer required Go imports from operation description.""" + imports = [] + logic_lower = logic_desc.lower() + + if any(word in logic_lower for word in ['file', 'directory', 'path', 'copy', 'move']): + imports.append('"io"') + imports.append('"path/filepath"') + + if any(word in logic_lower for word in ['json', 'parse']): + imports.append('"encoding/json"') + + if any(word in logic_lower for word in ['csv', 'comma']): + imports.append('"encoding/csv"') + + if any(word in logic_lower for word in ['http', 'api', 'request']): + imports.append('"net/http"') + + if any(word in logic_lower for word in ['string', 'text', 'replace']): + imports.append('"strings"') + + if any(word in logic_lower for word in ['regex', 'pattern', 'match']): + imports.append('"regexp"') + + if any(word in logic_lower for word in ['time', 'date', 'duration']): + imports.append('"time"') + + if any(word in logic_lower for word in ['concurrent', 'parallel', 'goroutine']): + imports.append('"sync"') + + if any(word in logic_lower for word in ['buffer', 'bytes']): + imports.append('"bytes"') + + return imports + +def generate_validation_logic(input_desc): + """Generate input validation logic.""" + validations = [] + + if 'file' in input_desc.lower(): + validations.append(dedent(''' + if flag.NArg() < 1 { + return fmt.Errorf("input file required") + } + inputFile := flag.Arg(0) + if _, err := os.Stat(inputFile); os.IsNotExist(err) { + return fmt.Errorf("input file does not exist: %s", inputFile) + } + ''').strip()) + + if 'directory' in input_desc.lower(): + validations.append(dedent(''' + if flag.NArg() < 1 { + return fmt.Errorf("input directory required") + } + inputDir := flag.Arg(0) + if info, err := os.Stat(inputDir); os.IsNotExist(err) || !info.IsDir() { + return fmt.Errorf("input directory does not exist: %s", inputDir) + } + ''').strip()) + + return '\n\t'.join(validations) if validations else '// No validation needed' + +def generate_run_logic(logic_desc, input_desc, output_desc): + """Generate main execution logic with placeholder.""" + logic_lower = logic_desc.lower() + + # Start with input handling + logic = [] + + if 'file' in input_desc.lower(): + logic.append('inputFile := flag.Arg(0)') + logic.append('') + + if 'directory' in input_desc.lower(): + logic.append('inputDir := flag.Arg(0)') + logic.append('') + + # Add operation-specific logic template + logic.append('// TODO: Implement the following logic:') + logic.append(f'// {logic_desc}') + logic.append('') + + if any(word in logic_lower for word in ['convert', 'transform', 'process']): + logic.append(dedent(''' + // 1. Read input + // 2. Process/transform data + // 3. Write output + ''').strip()) + + if 'parallel' in logic_lower or 'concurrent' in logic_lower: + logic.append(dedent(''' + // Consider using goroutines for parallel processing: + // var wg sync.WaitGroup + // for _, item := range items { + // wg.Add(1) + // go func(item Item) { + // defer wg.Done() + // // Process item + // }(item) + // } + // wg.Wait() + ''').strip()) + + # Add output handling + if 'stdout' in output_desc.lower(): + logic.append('') + logic.append('// Write results to stdout') + logic.append('fmt.Println(result)') + elif 'file' in output_desc.lower(): + logic.append('') + logic.append('outputFile := "output.txt" // TODO: Make configurable') + logic.append('if err := os.WriteFile(outputFile, []byte(result), 0644); err != nil {') + logic.append(' return fmt.Errorf("failed to write output: %w", err)') + logic.append('}') + + logic.append('') + logic.append('return nil') + + return '\n\t'.join(logic) + +def generate_helper_functions(logic_desc): + """Generate helper function templates.""" + helpers = [] + logic_lower = logic_desc.lower() + + if 'progress' in logic_lower or 'batch' in logic_lower: + helpers.append(dedent(''' + func showProgress(current, total int) { + if total > 0 { + percent := float64(current) / float64(total) * 100 + fmt.Fprintf(os.Stderr, "\\rProgress: %.1f%% (%d/%d)", percent, current, total) + if current == total { + fmt.Fprintln(os.Stderr) + } + } + } + ''').strip()) + + if 'validate' in logic_lower or 'check' in logic_lower: + helpers.append(dedent(''' + func validateInput(data interface{}) error { + // TODO: Implement validation logic + return nil + } + ''').strip()) + + return '\n\n'.join(helpers) if helpers else '// No helper functions needed' + +def determine_usage_args(input_desc): + """Determine usage string from input description.""" + if 'file' in input_desc.lower(): + return '' + elif 'directory' in input_desc.lower(): + return '' + else: + return '' + +def generate_go_script(name, description, input_desc, output_desc, logic_desc, skill_path): + """Generate a complete Go script.""" + + # Infer what imports we need + extra_imports = '\n\t'.join(infer_imports(logic_desc)) + + # Generate different sections + validation_logic = generate_validation_logic(input_desc) + run_logic = generate_run_logic(logic_desc, input_desc, output_desc) + helper_functions = generate_helper_functions(logic_desc) + usage_args = determine_usage_args(input_desc) + + # Fill in template + script_content = GO_SCRIPT_TEMPLATE.format( + description=description, + name=name, + input_desc=input_desc, + output_desc=output_desc, + usage_args=usage_args, + extra_imports=extra_imports, + validation_logic=validation_logic, + run_logic=run_logic, + helper_functions=helper_functions + ) + + return script_content + +def create_build_script(skill_path, script_name): + """Create a build script to compile the Go binary.""" + build_script = f'''#!/bin/bash +# Build script for {script_name} + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${{BASH_SOURCE[0]}}")" && pwd)" +BIN_DIR="$SCRIPT_DIR/bin" + +mkdir -p "$BIN_DIR" + +echo "Building {script_name}..." +cd "$SCRIPT_DIR" +go build -o "$BIN_DIR/{script_name}" {script_name}.go + +echo "✅ Built: $BIN_DIR/{script_name}" +echo "Run with: $BIN_DIR/{script_name} --help" +''' + + build_path = skill_path / 'scripts' / f'build_{script_name}.sh' + build_path.write_text(build_script) + build_path.chmod(0o755) + + return build_path + +def update_skill_md(skill_path, script_name, description, input_desc, output_desc): + """Add usage information to SKILL.md.""" + skill_md = skill_path / 'SKILL.md' + + if not skill_md.exists(): + print(f"⚠️ Warning: SKILL.md not found at {skill_md}") + return + + content = skill_md.read_text() + + # Add script documentation if not already present + script_section = f''' +### {script_name} + +{description} + +**Input:** {input_desc} +**Output:** {output_desc} + +**Usage:** +```bash +scripts/bin/{script_name} [options] +scripts/bin/{script_name} --help # For detailed options +``` + +**Example:** +```bash +scripts/bin/{script_name} input.txt +``` +''' + + if script_name not in content: + # Try to add after "## Resources" or at the end + if '## Resources' in content: + content = content.replace('## Resources', script_section + '\n## Resources') + else: + content += '\n' + script_section + + skill_md.write_text(content) + print(f"✅ Updated SKILL.md with {script_name} documentation") + else: + print(f"ℹ️ {script_name} already documented in SKILL.md") + +def main(): + parser = argparse.ArgumentParser( + description='Generate Go scripts for Claude Code skills', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=dedent(''' + Examples: + generate_go_script.py \\ + --name pdf-extract-text \\ + --description "Extract text from PDF files" \\ + --input "PDF file path" \\ + --output "Text content to stdout" \\ + --logic "Parse PDF and extract all text content" \\ + --skill-path ./my-pdf-skill + + generate_go_script.py \\ + --name csv-to-json \\ + --description "Convert CSV files to JSON" \\ + --input "CSV file path" \\ + --output "JSON file" \\ + --logic "Parse CSV rows and convert to JSON array" \\ + --skill-path ./data-tools + ''') + ) + + parser.add_argument('--name', required=True, help='Name of the script (e.g., pdf-to-images)') + parser.add_argument('--description', required=True, help='What the script does') + parser.add_argument('--input', required=True, help='Description of input') + parser.add_argument('--output', required=True, help='Description of output') + parser.add_argument('--logic', required=True, help='Description of the transformation logic') + parser.add_argument('--skill-path', required=True, help='Path to the skill directory') + parser.add_argument('--no-build', action='store_true', help='Skip creating build script') + parser.add_argument('--no-update-md', action='store_true', help='Skip updating SKILL.md') + + args = parser.parse_args() + + # Validate skill path + skill_path = Path(args.skill_path).resolve() + if not skill_path.exists(): + print(f"❌ Error: Skill path does not exist: {skill_path}") + sys.exit(1) + + # Create scripts directory if needed + scripts_dir = skill_path / 'scripts' + scripts_dir.mkdir(exist_ok=True) + + # Generate Go script + print(f"🚀 Generating Go script: {args.name}") + script_content = generate_go_script( + args.name, + args.description, + args.input, + args.output, + args.logic, + skill_path + ) + + # Write Go file + go_file = scripts_dir / f'{args.name}.go' + go_file.write_text(script_content) + print(f"✅ Created: {go_file}") + + # Create build script + if not args.no_build: + build_script = create_build_script(skill_path, args.name) + print(f"✅ Created build script: {build_script}") + print(f" Run: ./scripts/build_{args.name}.sh") + + # Update SKILL.md + if not args.no_update_md: + update_skill_md(skill_path, args.name, args.description, args.input, args.output) + + print(f"\n✅ Go script '{args.name}' generated successfully") + print("\nNext steps:") + print(f"1. Review and customize: {go_file}") + print(f"2. Build the binary: ./scripts/build_{args.name}.sh") + print(f"3. Test: ./scripts/bin/{args.name} --help") + +if __name__ == '__main__': + main() diff --git a/source/meta-skill-generator/scripts/init_skill_with_analysis.py b/source/meta-skill-generator/scripts/init_skill_with_analysis.py new file mode 100755 index 0000000..fd4777e --- /dev/null +++ b/source/meta-skill-generator/scripts/init_skill_with_analysis.py @@ -0,0 +1,280 @@ +#!/usr/bin/env python3 +""" +End-to-End Skill Creator with Workflow Analysis + +Guides through the complete process of creating a Claude Code skill with +intelligent Go script generation. + +Usage: + init_skill_with_analysis.py --path +""" + +import argparse +import subprocess +import sys +from pathlib import Path + +def run_command(cmd, cwd=None): + """Run a command and return success status.""" + try: + result = subprocess.run( + cmd, + cwd=cwd, + capture_output=True, + text=True, + check=True + ) + return True, result.stdout + except subprocess.CalledProcessError as e: + return False, e.stderr + +def gather_examples(): + """Gather example use cases from user.""" + print("\n" + "="*70) + print("STEP 1: GATHER EXAMPLE USE CASES") + print("="*70) + print("\nProvide 3-5 example requests that your skill should handle.") + print("Each example should be a concrete user request.") + print("Press Enter twice when done.\n") + + examples = [] + blank_count = 0 + + while blank_count < 2: + line = input(f"Example {len(examples)+1}: ").strip() + if not line: + blank_count += 1 + else: + blank_count = 0 + examples.append(line) + + if not examples: + print("Error: No examples provided") + sys.exit(1) + + return examples + +def analyze_workflow(examples): + """Analyze examples to identify operation types.""" + print("\n" + "="*70) + print("STEP 2: ANALYZING WORKFLOW") + print("="*70) + + # Create temporary file with examples + temp_file = Path("/tmp/skill_examples.txt") + temp_file.write_text('\n'.join(examples)) + + # Run analysis + script_path = Path(__file__).parent / "analyze_workflow.py" + cmd = [sys.executable, str(script_path), "--examples", str(temp_file)] + + success, output = run_command(cmd) + if not success: + print(f"Warning: Workflow analysis failed: {output}") + return None + + print(output) + return output + +def confirm_plan(): + """Ask user to confirm the plan.""" + print("\n" + "="*70) + print("Does this analysis look correct?") + response = input("Continue with skill creation? (y/n): ").lower() + return response == 'y' + +def initialize_skill(skill_name, path): + """Initialize skill directory structure.""" + print("\n" + "="*70) + print("STEP 3: INITIALIZING SKILL") + print("="*70) + + # Run init_skill.py + init_script = Path("/mnt/skills/examples/skill-creator/scripts/init_skill.py") + cmd = [sys.executable, str(init_script), skill_name, "--path", path] + + success, output = run_command(cmd) + if not success: + print(f"Error: Failed to initialize skill: {output}") + sys.exit(1) + + print(output) + return Path(path) / skill_name + +def gather_script_specs(skill_path): + """Gather specifications for Go scripts.""" + print("\n" + "="*70) + print("STEP 4: SPECIFY GO SCRIPTS") + print("="*70) + print("\nBased on the analysis, let's define the Go scripts.") + print("Enter details for each deterministic operation.") + print() + + scripts = [] + while True: + print(f"\n--- Go Script {len(scripts)+1} ---") + print("Press Enter with empty name to finish") + + name = input("Script name (e.g., pdf-to-images): ").strip() + if not name: + break + + description = input("Description: ").strip() + if not description: + print("Description required") + continue + + input_desc = input("Input (e.g., 'PDF file path'): ").strip() + if not input_desc: + print("Input description required") + continue + + output_desc = input("Output (e.g., 'Directory of PNG files'): ").strip() + if not output_desc: + print("Output description required") + continue + + logic = input("Logic (e.g., 'Extract each page at 300 DPI'): ").strip() + if not logic: + print("Logic description required") + continue + + scripts.append({ + 'name': name, + 'description': description, + 'input': input_desc, + 'output': output_desc, + 'logic': logic + }) + + print(f"✅ Script '{name}' configured") + + return scripts + +def generate_go_scripts(skill_path, scripts): + """Generate Go scripts using generate_go_script.py.""" + if not scripts: + print("\nNo Go scripts to generate") + return + + print("\n" + "="*70) + print("STEP 5: GENERATING GO SCRIPTS") + print("="*70) + + generator = Path(__file__).parent / "generate_go_script.py" + + for script in scripts: + print(f"\nGenerating {script['name']}...") + + cmd = [ + sys.executable, str(generator), + "--name", script['name'], + "--description", script['description'], + "--input", script['input'], + "--output", script['output'], + "--logic", script['logic'], + "--skill-path", str(skill_path) + ] + + success, output = run_command(cmd) + if not success: + print(f"⚠️ Warning: Failed to generate {script['name']}: {output}") + else: + print(f"✅ Generated {script['name']}") + +def finalize_skill_md(skill_path, examples): + """Add examples to SKILL.md.""" + print("\n" + "="*70) + print("STEP 6: FINALIZING SKILL.MD") + print("="*70) + + skill_md = skill_path / "SKILL.md" + content = skill_md.read_text() + + # Add examples section + examples_section = "\n## Example Use Cases\n\n" + for i, example in enumerate(examples, 1): + examples_section += f"{i}. {example}\n" + + # Insert before ## Resources section + if "## Resources" in content: + content = content.replace("## Resources", examples_section + "\n## Resources") + else: + content += examples_section + + skill_md.write_text(content) + print(f"✅ Updated SKILL.md with {len(examples)} example use cases") + +def print_next_steps(skill_path): + """Print next steps for the user.""" + print("\n" + "="*70) + print("✅ SKILL CREATED SUCCESSFULLY") + print("="*70) + print(f"\nSkill location: {skill_path}") + print("\nNext steps:") + print(f"1. Review and customize SKILL.md:") + print(f" - Complete the description in frontmatter") + print(f" - Add detailed workflow instructions") + print(f" - Remove TODO placeholders") + print() + print(f"2. Build Go scripts:") + print(f" cd {skill_path}") + for script_file in (skill_path / "scripts").glob("build_*.sh"): + print(f" ./{script_file.relative_to(skill_path)}") + print() + print(f"3. Test the scripts:") + for bin_file in (skill_path / "scripts" / "bin").glob("*"): + if bin_file.is_file(): + print(f" ./scripts/bin/{bin_file.name} --help") + print() + print(f"4. Package the skill:") + print(f" python3 /mnt/skills/examples/skill-creator/scripts/package_skill.py {skill_path}") + print() + +def main(): + parser = argparse.ArgumentParser( + description='Create a Claude Code skill with workflow analysis and Go script generation', + formatter_class=argparse.RawDescriptionHelpFormatter + ) + + parser.add_argument('skill_name', help='Name of the skill (e.g., pdf-tools)') + parser.add_argument('--path', required=True, help='Directory where skill will be created') + parser.add_argument('--skip-analysis', action='store_true', + help='Skip workflow analysis (use for simple skills)') + parser.add_argument('--skip-go', action='store_true', + help='Skip Go script generation (create structure only)') + + args = parser.parse_args() + + print("="*70) + print("CLAUDE CODE SKILL CREATOR") + print("="*70) + print(f"\nCreating skill: {args.skill_name}") + print(f"Location: {args.path}") + + # Step 1: Gather examples + examples = gather_examples() + + # Step 2: Analyze workflow (optional) + if not args.skip_analysis: + analysis = analyze_workflow(examples) + if analysis and not confirm_plan(): + print("\nAborted by user") + sys.exit(0) + + # Step 3: Initialize skill + skill_path = initialize_skill(args.skill_name, args.path) + + # Step 4-5: Generate Go scripts (optional) + if not args.skip_go: + scripts = gather_script_specs(skill_path) + generate_go_scripts(skill_path, scripts) + + # Step 6: Finalize + finalize_skill_md(skill_path, examples) + + # Done + print_next_steps(skill_path) + +if __name__ == '__main__': + main() diff --git a/source/meta-skill-generator/scripts/test_skill_scripts.py b/source/meta-skill-generator/scripts/test_skill_scripts.py new file mode 100755 index 0000000..175cb9b --- /dev/null +++ b/source/meta-skill-generator/scripts/test_skill_scripts.py @@ -0,0 +1,194 @@ +#!/usr/bin/env python3 +""" +Test runner for skill scripts + +Validates that all scripts in a skill are properly structured and executable. + +Usage: + test_skill_scripts.py +""" + +import argparse +import subprocess +import sys +from pathlib import Path + +def test_python_scripts(scripts_dir): + """Test Python scripts for syntax and executability.""" + results = [] + + for script in scripts_dir.glob("*.py"): + if script.name.startswith("test_") or script.name == "__init__.py": + continue + + # Check if executable + is_executable = script.stat().st_mode & 0o111 + + # Check syntax + try: + subprocess.run( + [sys.executable, "-m", "py_compile", str(script)], + capture_output=True, + check=True + ) + syntax_ok = True + except subprocess.CalledProcessError: + syntax_ok = False + + results.append({ + 'name': script.name, + 'type': 'python', + 'executable': is_executable, + 'syntax_ok': syntax_ok + }) + + return results + +def test_go_scripts(scripts_dir): + """Test Go scripts for compilation.""" + results = [] + + for script in scripts_dir.glob("*.go"): + # Try to compile + try: + result = subprocess.run( + ["go", "build", "-o", "/dev/null", str(script)], + capture_output=True, + check=True + ) + compiles = True + error = None + except subprocess.CalledProcessError as e: + compiles = False + error = e.stderr.decode() + except FileNotFoundError: + compiles = None # Go not installed + error = "Go compiler not found" + + results.append({ + 'name': script.name, + 'type': 'go', + 'compiles': compiles, + 'error': error + }) + + return results + +def test_bash_scripts(scripts_dir): + """Test Bash scripts for syntax.""" + results = [] + + for script in scripts_dir.glob("*.sh"): + # Check if executable + is_executable = script.stat().st_mode & 0o111 + + # Check syntax + try: + subprocess.run( + ["bash", "-n", str(script)], + capture_output=True, + check=True + ) + syntax_ok = True + except subprocess.CalledProcessError: + syntax_ok = False + + results.append({ + 'name': script.name, + 'type': 'bash', + 'executable': is_executable, + 'syntax_ok': syntax_ok + }) + + return results + +def print_results(results): + """Print test results.""" + print("\n" + "="*70) + print("SCRIPT TEST RESULTS") + print("="*70 + "\n") + + all_passed = True + + for result in results: + name = result['name'] + script_type = result['type'] + + print(f"{name} ({script_type})") + + if script_type == 'python': + if result['syntax_ok']: + print(" ✅ Syntax: OK") + else: + print(" ❌ Syntax: FAILED") + all_passed = False + + if result['executable']: + print(" ✅ Executable: Yes") + else: + print(" ⚠️ Executable: No (run: chmod +x)") + + elif script_type == 'go': + if result['compiles'] is None: + print(" ⚠️ Go compiler not found (skipped)") + elif result['compiles']: + print(" ✅ Compiles: OK") + else: + print(" ❌ Compiles: FAILED") + if result['error']: + print(f" Error: {result['error'][:100]}") + all_passed = False + + elif script_type == 'bash': + if result['syntax_ok']: + print(" ✅ Syntax: OK") + else: + print(" ❌ Syntax: FAILED") + all_passed = False + + if result['executable']: + print(" ✅ Executable: Yes") + else: + print(" ⚠️ Executable: No (run: chmod +x)") + + print() + + return all_passed + +def main(): + parser = argparse.ArgumentParser( + description='Test all scripts in a skill directory' + ) + parser.add_argument('skill_path', help='Path to skill directory') + + args = parser.parse_args() + + skill_path = Path(args.skill_path).resolve() + scripts_dir = skill_path / 'scripts' + + if not scripts_dir.exists(): + print(f"Error: scripts directory not found: {scripts_dir}") + sys.exit(1) + + print(f"Testing scripts in: {scripts_dir}") + + results = [] + results.extend(test_python_scripts(scripts_dir)) + results.extend(test_go_scripts(scripts_dir)) + results.extend(test_bash_scripts(scripts_dir)) + + if not results: + print("No scripts found to test") + sys.exit(0) + + all_passed = print_results(results) + + if all_passed: + print("✅ All tests passed!") + sys.exit(0) + else: + print("❌ Some tests failed") + sys.exit(1) + +if __name__ == '__main__': + main()