This file is for coding agents working in this repository. Keep it accurate when the build, generation flow, or project layout changes.
DSPex provides DSPy for Elixir through SnakeBridge. There are two public access layers:
DSPexinlib/dspex.ex: hand-written convenience wrapper overSnakeBridge.call/4,SnakeBridge.call!/4, and related FFI helpers.Dspy.*inlib/snakebridge_generated/dspy: generated SnakeBridge bindings for the Pythondspypackage.
The generated modules are intentionally checked in. They are used for HexDocs, IDE navigation, and direct Elixir access to DSPy's public API surface.
mix.exs: package metadata, deps, SnakeBridge compiler, and Python dependency declaration.config/config.exs: SnakeBridge config.generated_layout: :splitmeans generation writes many per-module files underlib/snakebridge_generated.snakebridge.lock: generation/runtime metadata, requested/resolved Python package versions, and generator hashes.lib/dspex.ex: hand-written public convenience API.lib/snakebridge_generated/**: generated files. Do not hand-edit these.examples/README.md,guides/*.md: user-facing workflow docs.CHANGELOG.md: update the[Unreleased]section for dependency and generated surface changes.
- Do not manually edit files under
lib/snakebridge_generated. - If generated output is wrong, change SnakeBridge, the Python dependency config, or the upstream Python package version, then regenerate.
- Generated file headers should show the current SnakeBridge and DSPy versions,
for example
# Library: dspy 3.2.0. Dspy.*modules are thin wrappers overSnakeBridge.Runtime; they should contain__snakebridge_python_name__/0, optional__snakebridge_python_class__/0,__snakebridge_library__/0,new/3for classes, and method/function wrappers that callSnakeBridge.Runtime.
Use this flow when bumping the Python dspy dependency:
-
Check the worktree:
git status --short
-
Update the DSPy version in
mix.exs:{:dspy, "x.y.z", generate: :all, module_mode: :explicit, max_class_methods: 500}
-
Add a
[Unreleased]changelog note saying DSPy was upgraded and the generatedDspy.*wrapper surface was regenerated. -
Remove old generated artifacts:
rm -rf lib/snakebridge_generated
-
Regenerate:
HEX_HOME=/tmp/dspex_hex_home mix snakebridge.regen --clean
HEX_HOME=/tmp/dspex_hex_homeavoids failures from a broken user-level Hex config. If Hex is healthy in the environment, plainmix snakebridge.regen --cleanis fine. -
Confirm the lock file and generated headers:
rg -n '"requested":|"resolved":|"version":' snakebridge.lock rg -n 'Library: dspy|Requested:|Observed at generation:' lib/snakebridge_generated | head -n 80
-
Check generated file count and new/deleted files:
find lib/snakebridge_generated -type f -name '*.ex' | sort | wc -l git status --short
Prefer these commands after code or generation changes:
HEX_HOME=/tmp/dspex_hex_home mix compile
HEX_HOME=/tmp/dspex_hex_home mix testRun examples with --no-start so DSPex owns the Snakepit lifecycle:
mix run --no-start examples/basic.exsMost examples require GEMINI_API_KEY. RLM examples also require Deno.
- Local
mix help ...can fail if the user-level Hex config is invalid. Retry withHEX_HOME=/tmp/dspex_hex_home. - Do not run
mix runexamples without--no-start; the docs use--no-startto avoid unclean Snakepit DETS shutdown warnings. - Generated modules may be numerous and noisy in diffs. Review high-level
signals first: version headers, new/deleted modules, lock metadata, and
whether
mix compilepasses. - The generated surface uses
module_mode: :explicitby design. Do not switch to broader discovery unless the user explicitly wants a much larger surface. max_class_methods: 500is a guardrail for inheritance-heavy DSPy classes. Keep it unless there is a specific missing-method reason to change it.
mix.exsrequests the intended DSPy version.snakebridge.lockrequested/resolved/version entries match the intended DSPy version.- Generated headers mention the intended DSPy version.
- New generated files are plausible for the upstream DSPy release.
- No hand-written files under
lib/changed unintentionally, except deliberate updates such aslib/dspex.ex. CHANGELOG.mdhas an[Unreleased]note.mix compilepasses.mix testpasses, or the failure is recorded with the exact reason.
When the user asks to cut or prepare a release version:
- Update
@versioninmix.exs. - Update the README install snippet (
{:dspex, "~> x.y.z"}). - Move relevant
[Unreleased]changelog notes into## [x.y.z] - YYYY-MM-DD. - Add the matching changelog compare link and advance
[Unreleased]to compare from the new tag. - Search the repo for the old version and review every remaining hit:
rg -n 'old\\.version|new\\.version' README.md CHANGELOG.md mix.exs examples guides config lib test AGENTS.md