/dspy-fundamentals
Write idiomatic DSPy 3.2.x programs — typed Signatures, dspy.Module subclasses, Predict/ChainOfThought/ReAct/ProgramOfThought, and save/load. Use this when starting any new DSPy project or when fixing non-idiomatic DSPy code (hard-coded prompts, ad-hoc string templates, untyped
$ npx -y skills add intertwine/dspy-agent-skills --skill dspy-fundamentals --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/dspy-fundamentals
Context preview
The summary Claude sees to decide when to auto-load this skill.
Write idiomatic DSPy 3.2.x programs — typed Signatures, dspy.Module subclasses, Predict/ChainOfThought/ReAct/ProgramOfThought, and save/load. Use this when starting any new DSPy project or when fixing non-idiomatic DSPy code (hard-coded prompts, ad-hoc string templates, untyped
SKILL.md
dspy-fundamentals.SKILL.mdname: dspy-fundamentals
description: Write idiomatic DSPy 3.2.x programs — typed Signatures, dspy.Module subclasses, Predict/ChainOfThought/ReAct/ProgramOfThought, and save/load. Use this when starting any new DSPy project or when fixing non-idiomatic DSPy code (hard-coded prompts, ad-hoc string templates, untyped outputs, non-serializable classes).
when_to_use: User mentions DSPy, writes a file that imports `dspy`, asks to build an LLM pipeline/program/agent with structured inputs/outputs, or requests refactoring of prompt-engineering code into a programmatic framework.
DSPy Fundamentals (3.2.x)
DSPy is the "PyTorch for prompts" — you declare **Signatures** (typed I/O contracts), compose them into **Modules**, and let optimizers (not you) tune the instructions and few-shot examples. Never write raw prompts.
The one-paragraph model
Configure a single LM globally with `dspy.configure(lm=...)`. Define a `dspy.Signature` subclass with `dspy.InputField()` / `dspy.OutputField()` (docstring becomes the instruction). Wrap it in a predictor — `dspy.Predict` (direct), `dspy.ChainOfThought` (adds reasoning), `dspy.ReAct` (tool-using agent), `dspy.ProgramOfThought` (code-executing), or `dspy.RLM` (long-context). Subclass `dspy.Module` to compose multi-step programs. For built-in providers, use `dspy.LM("provider/model")`; for a truly custom backend, subclass `dspy.BaseLM`. Optimize later with GEPA.
Canonical template
import dspy
dspy.configure(lm=dspy.LM("openai/gpt-4o"), track_usage=True)
class QuestionAnswer(dspy.Signature):
"""Answer questions with rigorous step-by-step reasoning."""
question: str = dspy.InputField()
answer: str = dspy.OutputField(desc="concise final answer")
class QAProgram(dspy.Module):
def __init__(self):
super().__init__()
self.solve = dspy.ChainOfThought(QuestionAnswer)
def forward(self, question: str) -> dspy.Prediction:
return self.solve(question=question)
program = QAProgram()
pred = program(question="What is 2 + 2?")
print(pred.reasoning, pred.answer)Predictor cheatsheet (DSPy 3.2.x)
| Predictor | When to use | Adds | |---|---|---| | `dspy.Predict(sig)` | Simple structured I/O | nothing — just the signature | | `dspy.ChainOfThought(sig)` | Reasoning tasks | a `reasoning` output field | | `dspy.ReAct(sig, tools=[...], max_iters=20)` | Tool-using agent | Thought/Action/Observation loop | | `dspy.ProgramOfThought(sig, max_iters=3)` | Math/data tasks | generates & runs Python (needs Deno) | | `dspy.RLM(sig, ...)` | Long context / codebases | recursive REPL exploration (see `dspy-rlm-module`) |
Typed outputs — use Pydantic on fields, not `TypedPredictor`
`dspy.TypedPredictor` is superseded; `dspy.Predict` now handles Pydantic types natively via field annotations.
from pydantic import BaseModel
from typing import Literal
class Entity(BaseModel):
name: str
kind: Literal["person", "org", "place"]
class ExtractEntities(dspy.Signature):
"""Extract named entities from text."""
text: str = dspy.InputField()
entities: list[Entity] = dspy.OutputField()
extractor = dspy.Predict(ExtractEntities)Save & load
Two modes — know the difference:
# State-only (portable JSON; you must rebuild the architecture to load)
program.save("program.json", save_program=False)
new = QAProgram(); new.load("program.json")
# Full program (cloudpickle into a directory; restores everything)
program.save("./program_dir/", save_program=True)
restored = dspy.load("./program_dir/")Prefer state-only for version control; full-program for deployment artifacts.
Ten anti-patterns to refuse
1. Hard-coded prompt strings (`"You are a helpful assistant..."`) — write a Signature. 2. `dspy.TypedPredictor(...)` in new code — use `dspy.Predict` with Pydantic fields. 3. `dspy.OpenAI(...)` / `dspy.settings.configure(...)` — use `dspy.configure(lm=dspy.LM(...))`. 4. Provider-specific LM classes for built-in providers — use `dspy.LM("provider/model")`. If DSPy doesn't ship your backend, subclass `dspy.BaseLM`. 5. Giant monolithic predictors that do five jobs — decompose into a `Module` with named sub-predictors. 6. Mutating `signature.instructions` by hand — let the optimizer do it. 7. In-lining few-shot demos in the Signature docstring — bootstrap/optimize them. 8. Using `pickle.dump(program)` — use `program.save(...)`. 9. Setting an LM per module at construction time without reason — configure globally, override only when you need model mixing. 10. Vague metrics (yes/no, exact-match only) when training an optimizer — see `dspy-evaluation-harness`.
Configuring the LM
dspy.configure(
lm=dspy.LM("openai/gpt-4o", temperature=0.0, max_tokens=2000),
track_usage=True, # accumulate token counts on predictions
async_max_workers=4, # for .acall / batch
)DSPy 3.2.x warns by default when a module call passes extra input fields or values that don't match the signature's declared types. Treat those warnings as a callsite bug first; if you're intentionally passing pre-serialized values, disable them with `dspy.configure(warn_on_type_mismatch=False)`.
Common provider prefixes: `openai/`, `anthropic/`, `azure/`, `vertex_ai/`, `bedrock/`, `ollama/`. For local Ollama: `dspy.LM("ollama_chat/llama3.1:8b", api_base="http://localhost:11434")`.
Where to go next
- Measuring quality → `dspy-evaluation-harness`
- Automatic optimization → `dspy-gepa-optimizer`
- Context >100k tokens → `dspy-rlm-module`
- Full pipeline → `dspy-advanced-workflow`
- Full API reference → [reference.md](reference.md)
- Runnable example → [example_qa.py](example_qa.py)
Read more
name: dspy-fundamentals description: Write idiomatic DSPy 3.2.x programs — typed Signatures, dspy.Module subclasses, Predict/ChainOfThought/ReAct/ProgramOfThought, and save/load. Use this when starting any new DSPy project or when fixing non-idiomatic DSPy code (hard-coded prompts, ad-hoc string templates, untyped outputs, non-serializable classes). when_to_use: User mentions DSPy, writes a file that imports `dspy`, asks to build an LLM pipeline/program/agent with structured inputs/outputs, or requests refactoring of prompt-engineering code into a programmatic framework.
DSPy Fundamentals (3.2.x)
DSPy is the "PyTorch for prompts" — you declare **Signatures** (typed I/O contracts), compose them into **Modules**, and let optimizers (not you) tune the instructions and few-shot examples. Never write raw prompts.
The one-paragraph model
Configure a single LM globally with `dspy.configure(lm=...)`. Define a `dspy.Signature` subclass with `dspy.InputField()` / `dspy.OutputField()` (docstring becomes the instruction). Wrap it in a predictor — `dspy.Predict` (direct), `dspy.ChainOfThought` (adds reasoning), `dspy.ReAct` (tool-using agent), `dspy.ProgramOfThought` (code-executing), or `dspy.RLM` (long-context). Subclass `dspy.Module` to compose multi-step programs. For built-in providers, use `dspy.LM("provider/model")`; for a truly custom backend, subclass `dspy.BaseLM`. Optimize later with GEPA.
Canonical template
import dspy
dspy.configure(lm=dspy.LM("openai/gpt-4o"), track_usage=True)
class QuestionAnswer(dspy.Signature):
"""Answer questions with rigorous step-by-step reasoning."""
question: str = dspy.InputField()
answer: str = dspy.OutputField(desc="concise final answer")
class QAProgram(dspy.Module):
def __init__(self):
super().__init__()
self.solve = dspy.ChainOfThought(QuestionAnswer)
def forward(self, question: str) -> dspy.Prediction:
return self.solve(question=question)
program = QAProgram()
pred = program(question="What is 2 + 2?")
print(pred.reasoning, pred.answer)Predictor cheatsheet (DSPy 3.2.x)
| Predictor | When to use | Adds | |---|---|---| | `dspy.Predict(sig)` | Simple structured I/O | nothing — just the signature | | `dspy.ChainOfThought(sig)` | Reasoning tasks | a `reasoning` output field | | `dspy.ReAct(sig, tools=[...], max_iters=20)` | Tool-using agent | Thought/Action/Observation loop | | `dspy.ProgramOfThought(sig, max_iters=3)` | Math/data tasks | generates & runs Python (needs Deno) | | `dspy.RLM(sig, ...)` | Long context / codebases | recursive REPL exploration (see `dspy-rlm-module`) |
Typed outputs — use Pydantic on fields, not `TypedPredictor`
`dspy.TypedPredictor` is superseded; `dspy.Predict` now handles Pydantic types natively via field annotations.
from pydantic import BaseModel
from typing import Literal
class Entity(BaseModel):
name: str
kind: Literal["person", "org", "place"]
class ExtractEntities(dspy.Signature):
"""Extract named entities from text."""
text: str = dspy.InputField()
entities: list[Entity] = dspy.OutputField()
extractor = dspy.Predict(ExtractEntities)Save & load
Two modes — know the difference:
# State-only (portable JSON; you must rebuild the architecture to load)
program.save("program.json", save_program=False)
new = QAProgram(); new.load("program.json")
# Full program (cloudpickle into a directory; restores everything)
program.save("./program_dir/", save_program=True)
restored = dspy.load("./program_dir/")Prefer state-only for version control; full-program for deployment artifacts.
Ten anti-patterns to refuse
1. Hard-coded prompt strings (`"You are a helpful assistant..."`) — write a Signature. 2. `dspy.TypedPredictor(...)` in new code — use `dspy.Predict` with Pydantic fields. 3. `dspy.OpenAI(...)` / `dspy.settings.configure(...)` — use `dspy.configure(lm=dspy.LM(...))`. 4. Provider-specific LM classes for built-in providers — use `dspy.LM("provider/model")`. If DSPy doesn't ship your backend, subclass `dspy.BaseLM`. 5. Giant monolithic predictors that do five jobs — decompose into a `Module` with named sub-predictors. 6. Mutating `signature.instructions` by hand — let the optimizer do it. 7. In-lining few-shot demos in the Signature docstring — bootstrap/optimize them. 8. Using `pickle.dump(program)` — use `program.save(...)`. 9. Setting an LM per module at construction time without reason — configure globally, override only when you need model mixing. 10. Vague metrics (yes/no, exact-match only) when training an optimizer — see `dspy-evaluation-harness`.
Configuring the LM
dspy.configure(
lm=dspy.LM("openai/gpt-4o", temperature=0.0, max_tokens=2000),
track_usage=True, # accumulate token counts on predictions
async_max_workers=4, # for .acall / batch
)DSPy 3.2.x warns by default when a module call passes extra input fields or values that don't match the signature's declared types. Treat those warnings as a callsite bug first; if you're intentionally passing pre-serialized values, disable them with `dspy.configure(warn_on_type_mismatch=False)`.
Common provider prefixes: `openai/`, `anthropic/`, `azure/`, `vertex_ai/`, `bedrock/`, `ollama/`. For local Ollama: `dspy.LM("ollama_chat/llama3.1:8b", api_base="http://localhost:11434")`.
Where to go next
- Measuring quality → `dspy-evaluation-harness`
- Automatic optimization → `dspy-gepa-optimizer`
- Context >100k tokens → `dspy-rlm-module`
- Full pipeline → `dspy-advanced-workflow`
- Full API reference → [reference.md](reference.md)
- Runnable example → [example_qa.py](example_qa.py)
Production-grade DSPy 3.2.x skills for coding agents. A synthesized, spec-compliant pack of five agent skills that turns Claude Code, Codex CLI, and any other agentskills.io-compatible agent into a DSPy expert.
Other skills on dspy-agent-skills.
- /dspy-advanced-workflow
Drive a complete DSPy 3.2.x project end-to-end — spec → program → metric → baseline → GEPA optimize → export → deploy. Orchestrates the other four DSPy skills (dspy-fundamentals, dspy-evaluation-harness, dspy-gepa-optimizer, dspy-rlm-module) in the correct order. Use this for
Open skill - /dspy-evaluation-harness
Build DSPy evaluation harnesses with rich-feedback metrics that are essential for GEPA optimization. Use when writing a metric function, calling dspy.Evaluate, splitting dev/val sets, debugging "why is my optimizer not improving?", or designing CI-ready DSPy eval suites.
Open skill - /dspy-gepa-optimizer
Optimize DSPy programs with dspy.GEPA — the reflective/evolutionary optimizer that is the 2026 gold standard for DSPy (beats MIPROv2 on complex tasks with far fewer rollouts when the metric returns rich feedback). Use when the user says optimize, compile, GEPA, reflective
Open skill - /dspy-rlm-module
Use dspy.RLM (Recursive Language Model) for reasoning over contexts too large to fit in an LLM's working window — entire codebases, long logs, massive documents, or multi-step data exploration that needs a sandboxed Python REPL. Use when the input is >100k tokens, needs
Open skill

