# Deterministic Scripting Pattern

## Purpose

Shift mechanical, repeatable work from AI context to deterministic scripts. Scripts improve consistency, reduce context bloat, and let AI focus on judgment-based work.

This pattern applies during skill design and planning phases. The AI should recognize scripting opportunities and recommend them, rather than asking the user unprompted.

## Core Principle

When the AI encounters a task component during planning, it should ask:

> "Is this mechanical, repeatable, and unambiguous? If yes, a script will do this more reliably than I can."

Scripts are not replacements for AI judgment—they're complements. Scripts handle the deterministic foundation; AI handles interpretation and decisions built on that foundation.

## Quick Heuristics

Self-check during planning:

1. **Binary correctness?** - Is the output valid/invalid rather than good/better/best?
2. **Identical execution?** - Would I do this the same way every time?
3. **Structured data?** - Does it involve parsing, transforming, or validating structured formats?
4. **No interpretation?** - Can correctness be determined without judgment?

If 3+ answers are "yes" → strong script candidate.

## Examples

| Task | Script? | Reasoning |
|------|---------|-----------|
| Validate YAML frontmatter | Yes | Binary correctness, structured data |
| Scaffold directory structure | Yes | Deterministic file operations |
| Parse and normalize field values | Yes | Mechanical transformation |
| Check description length limits | Yes | Quantitative constraint |
| Verify naming conventions | Yes | Pattern matching, no judgment |
| Generate boilerplate from template | Yes | Deterministic substitution |
| Evaluate description quality | No | Qualitative judgment required |
| Choose between design approaches | No | Trade-off analysis |
| Assess code readability | No | Subjective evaluation |
| Decide what to include in a skill | No | Requires understanding intent |

### Hybrid Tasks

Some tasks appear qualitative but have quantitative components scripts can handle:

| Task | Script Portion | AI Portion |
|------|----------------|------------|
| Review description | Length limits, forbidden characters, required fields | Clarity, specificity, tone |
| Audit skill structure | File existence, naming conventions, size limits | Content quality, completeness |
| Validate workflow | Required sections present, link validity | Logical flow, clarity |

**Principle:** Extract quantitative guardrails into scripts. Let AI focus on the qualitative judgment that remains.

## Language Selection

Choose language based on project context and tool fit, not personal preference.

### Principles

1. **Match project context** - A Ruby script in a Rails project integrates naturally. A Python script in a Rails project adds cognitive overhead.

2. **Use best-in-class for domains** - Some tools have clear language winners. Playwright is best supported in Python. Data science tasks favor Python. Shell automation favors Bash.

3. **Prefer OOP-capable languages** - Ruby, Python, JavaScript/TypeScript support clean object-oriented design. Bash does not—use it only for simple orchestration or when it's genuinely the best fit.

4. **Consider maintenance** - Who will maintain this script? If the project team knows Ruby, write Ruby. If you're building a general-purpose skill, Python has broader reach.

### Examples

| Project Context | Recommended | Reasoning |
|-----------------|-------------|-----------|
| Rails application | Ruby | Matches project, team knows it |
| Ruby gem | Ruby | Same ecosystem, natural fit |
| General-purpose skill | Python | Broad reach, well-supported |
| Browser automation | Python | Playwright's best support |
| Data transformation | Python | Rich ecosystem (pandas, etc.) |
| Simple file operations | Bash | Lightweight, universal |
| Node.js project | JavaScript/TypeScript | Matches project context |
| Cross-platform CLI tool | Python or Go | Portability matters |

### Anti-patterns

- Writing Bash for complex logic (use a real language)
- Choosing Python for a Ruby project because "Python is more popular"
- Using JavaScript for non-JS projects just because you know it
- Mixing languages within a single skill's scripts without good reason

## OOP Principles

Scripts should follow object-oriented principles for maintainability and evolution. These principles, drawn from Sandi Metz's teachings, apply to Ruby, Python, and JavaScript alike.

### Single Responsibility

Each class/module does one thing. Each method does one thing.

```ruby
# Good: Single responsibility
class FrontmatterValidator
  def validate(content)
    # Only validates frontmatter
  end
end

class StructureValidator
  def validate(path)
    # Only validates directory structure
  end
end

# Bad: Multiple responsibilities
class SkillValidator
  def validate_everything(path)
    # Validates frontmatter AND structure AND content AND...
  end
end
```

### Dependency Injection

Objects receive their dependencies; they don't create them.

```python
# Good: Dependencies injected
class SkillScaffolder:
    def __init__(self, file_system, template_loader):
        self.fs = file_system
        self.templates = template_loader

# Bad: Dependencies created internally
class SkillScaffolder:
    def __init__(self):
        self.fs = RealFileSystem()  # Hard to test
        self.templates = TemplateLoader()  # Tightly coupled
```

### Small, Composable Objects

Prefer many small objects over few large ones. Compose behavior through collaboration.

```ruby
# Good: Small, composable
validator = CompositeValidator.new([
  NameValidator.new,
  FrontmatterValidator.new,
  StructureValidator.new
])

# Bad: Monolithic
validator = MegaValidator.new  # 500 lines, does everything
```

### Immutable Data Where Possible

Prefer transformations that return new objects over mutations.

```python
# Good: Returns new object
def with_updated_name(skill, new_name):
    return Skill(name=new_name, **skill.other_attrs)

# Bad: Mutates in place
def update_name(skill, new_name):
    skill.name = new_name  # Side effect
```

### Tell, Don't Ask

Tell objects what to do; don't ask for their data and make decisions externally.

```ruby
# Good: Tell the object
validator.validate_and_report(skill_path)

# Bad: Ask and decide externally
if validator.has_frontmatter?(skill_path) && validator.frontmatter_valid?(skill_path)
  # External decision-making
end
```

## Integration with Workflows

This pattern integrates at two points:

### During Brainstorming

When refining a skill concept, the AI should identify script candidates:

> "This skill involves validating workflow YAML and scaffolding directories. Both are mechanical tasks—I recommend scripts for consistency. The qualitative review of workflow clarity stays with the AI."

### During Planning (new-skill workflow)

Step 2 (Analyze and Plan) should explicitly consider:
- Which components are script candidates?
- What language fits this project?
- What quantitative guardrails can be extracted?

The planning output should list identified scripts before implementation begins.

## Model Guidance

| Task | Recommended Model |
|------|-------------------|
| Writing scripts | Haiku (mechanical, clear requirements) |
| Designing script interfaces | Opus (API design is judgment) |
| Reviewing script correctness | Haiku (mechanical verification) |
| Deciding what to script | Opus (requires understanding intent) |

## Verification

Two distinct concepts:

**Scripts must be verifiable** - Scripts themselves should be reliable and testable:
1. **Exit codes** - 0 for success, non-zero for failure
2. **Structured output** - JSON or clear text for parsing
3. **Idempotent** - Running twice produces same result
4. **Testable** - Can be run in isolation with test inputs

**Scripts as verification tools** - Scripts can serve as verification mechanisms for skills:
```bash
python scripts/validate_skill.py path/to/skill
# Exit code 0 = valid, 1 = invalid
# Output describes any issues found
```

This complements the Verification Pattern—scripts provide deterministic evidence that work is complete and correct.

## Anti-patterns

### Over-scripting

Not everything needs a script. If a task requires judgment, context, or interpretation, keep it in AI domain.

**Signs of over-scripting:**
- Script has many special cases and edge case handling
- Script needs to "understand" content, not just parse it
- Script requires frequent updates as requirements evolve
- Script is longer than the AI instructions it replaced

### Under-scripting

Repeated mechanical work that stays in AI context wastes tokens and introduces inconsistency.

**Signs of under-scripting:**
- Same validation logic described in multiple places
- AI makes occasional errors on mechanical tasks
- Structured data processed differently each time
- No verification possible because there's no script to run

### Wrong Abstraction Level

Scripts should operate at the right level—not too granular, not too broad.

**Too granular:** Separate scripts for checking each frontmatter field
**Too broad:** One script that validates, scaffolds, and generates content
**Right level:** One script for frontmatter validation, one for scaffolding, one for structure checks
