Files
claude-engineering-plugin/plugins/compounding-engineering/skills/dspy-ruby/references/core-concepts.md
Kieran Klaassen 8cc99ab483 feat(plugin): reorganize compounding-engineering v2.0.0
Major restructure of the compounding-engineering plugin:

## Agents (24 total, now categorized)
- review/ (10): architecture-strategist, code-simplicity-reviewer,
  data-integrity-guardian, dhh-rails-reviewer, kieran-rails-reviewer,
  kieran-python-reviewer, kieran-typescript-reviewer,
  pattern-recognition-specialist, performance-oracle, security-sentinel
- research/ (4): best-practices-researcher, framework-docs-researcher,
  git-history-analyzer, repo-research-analyst
- design/ (3): design-implementation-reviewer, design-iterator,
  figma-design-sync
- workflow/ (6): bug-reproduction-validator, every-style-editor,
  feedback-codifier, lint, pr-comment-resolver, spec-flow-analyzer
- docs/ (1): ankane-readme-writer

## Commands (15 total)
- Moved workflow commands to commands/workflows/ subdirectory
- Added: changelog, create-agent-skill, heal-skill, plan_review,
  prime, reproduce-bug, resolve_parallel, resolve_pr_parallel

## Skills (11 total)
- Added: andrew-kane-gem-writer, codify-docs, create-agent-skills,
  dhh-ruby-style, dspy-ruby, every-style-editor, file-todos,
  frontend-design, git-worktree, skill-creator
- Kept: gemini-imagegen

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 11:42:18 -08:00

6.2 KiB

DSPy.rb Core Concepts

Philosophy

DSPy.rb enables developers to program LLMs, not prompt them. Instead of manually crafting prompts, define application requirements through code using type-safe, composable modules.

Signatures

Signatures define type-safe input/output contracts for LLM operations. They specify what data goes in and what data comes out, with runtime type checking.

Basic Signature Structure

class TaskSignature < DSPy::Signature
  description "Brief description of what this signature does"

  input do
    const :field_name, String, desc: "Description of this input field"
    const :another_field, Integer, desc: "Another input field"
  end

  output do
    const :result_field, String, desc: "Description of the output"
    const :confidence, Float, desc: "Confidence score (0.0-1.0)"
  end
end

Type Safety

Signatures support Sorbet types including:

  • String - Text data
  • Integer, Float - Numeric data
  • T::Boolean - Boolean values
  • T::Array[Type] - Arrays of specific types
  • Custom enums and classes

Field Descriptions

Always provide clear field descriptions using the desc: parameter. These descriptions:

  • Guide the LLM on expected input/output format
  • Serve as documentation for developers
  • Improve prediction accuracy

Modules

Modules are composable building blocks that use signatures to perform LLM operations. They can be chained together to create complex workflows.

Basic Module Structure

class MyModule < DSPy::Module
  def initialize
    super
    @predictor = DSPy::Predict.new(MySignature)
  end

  def forward(input_hash)
    @predictor.forward(input_hash)
  end
end

Module Composition

Modules can call other modules to create pipelines:

class ComplexWorkflow < DSPy::Module
  def initialize
    super
    @step1 = FirstModule.new
    @step2 = SecondModule.new
  end

  def forward(input)
    result1 = @step1.forward(input)
    result2 = @step2.forward(result1)
    result2
  end
end

Predictors

Predictors are the core execution engines that take signatures and perform LLM inference. DSPy.rb provides several predictor types.

Predict

Basic LLM inference with type-safe inputs and outputs.

predictor = DSPy::Predict.new(TaskSignature)
result = predictor.forward(field_name: "value", another_field: 42)
# Returns: { result_field: "...", confidence: 0.85 }

ChainOfThought

Automatically adds a reasoning field to the output, improving accuracy for complex tasks.

class EmailClassificationSignature < DSPy::Signature
  description "Classify customer support emails"

  input do
    const :email_subject, String
    const :email_body, String
  end

  output do
    const :category, String  # "Technical", "Billing", or "General"
    const :priority, String  # "High", "Medium", or "Low"
  end
end

predictor = DSPy::ChainOfThought.new(EmailClassificationSignature)
result = predictor.forward(
  email_subject: "Can't log in to my account",
  email_body: "I've been trying to access my account for hours..."
)
# Returns: {
#   reasoning: "This appears to be a technical issue...",
#   category: "Technical",
#   priority: "High"
# }

ReAct

Tool-using agents with iterative reasoning. Enables autonomous problem-solving by allowing the LLM to use external tools.

class SearchTool < DSPy::Tool
  def call(query:)
    # Perform search and return results
    { results: search_database(query) }
  end
end

predictor = DSPy::ReAct.new(
  TaskSignature,
  tools: [SearchTool.new],
  max_iterations: 5
)

CodeAct

Dynamic code generation for solving problems programmatically. Requires the optional dspy-code_act gem.

predictor = DSPy::CodeAct.new(TaskSignature)
result = predictor.forward(task: "Calculate the factorial of 5")
# The LLM generates and executes Ruby code to solve the task

Multimodal Support

DSPy.rb supports vision capabilities across compatible models using the unified DSPy::Image interface.

class VisionSignature < DSPy::Signature
  description "Describe what's in an image"

  input do
    const :image, DSPy::Image
    const :question, String
  end

  output do
    const :description, String
  end
end

predictor = DSPy::Predict.new(VisionSignature)
result = predictor.forward(
  image: DSPy::Image.from_file("path/to/image.jpg"),
  question: "What objects are visible in this image?"
)

Image Input Methods

# From file path
DSPy::Image.from_file("path/to/image.jpg")

# From URL (OpenAI only)
DSPy::Image.from_url("https://example.com/image.jpg")

# From base64-encoded data
DSPy::Image.from_base64(base64_string, mime_type: "image/jpeg")

Best Practices

1. Clear Signature Descriptions

Always provide clear, specific descriptions for signatures and fields:

# Good
description "Classify customer support emails into Technical, Billing, or General categories"

# Avoid
description "Classify emails"

2. Type Safety

Use specific types rather than generic String when possible:

# Good - Use enums for constrained outputs
output do
  const :category, T.enum(["Technical", "Billing", "General"])
end

# Less ideal - Generic string
output do
  const :category, String, desc: "Must be Technical, Billing, or General"
end

3. Composable Architecture

Build complex workflows from simple, reusable modules:

class EmailPipeline < DSPy::Module
  def initialize
    super
    @classifier = EmailClassifier.new
    @prioritizer = EmailPrioritizer.new
    @responder = EmailResponder.new
  end

  def forward(email)
    classification = @classifier.forward(email)
    priority = @prioritizer.forward(classification)
    @responder.forward(classification.merge(priority))
  end
end

4. Error Handling

Always handle potential type validation errors:

begin
  result = predictor.forward(input_data)
rescue DSPy::ValidationError => e
  # Handle validation error
  logger.error "Invalid output from LLM: #{e.message}"
end

Limitations

Current constraints to be aware of:

  • No streaming support (single-request processing only)
  • Limited multimodal support through Ollama for local deployments
  • Vision capabilities vary by provider (see providers.md for compatibility matrix)