qlaw-dspy) is the Qlaw reasoning engine re-implemented on DSPy 3.3.0 as a compilable, evaluable program. Qlaw’s agents become typed dspy.Signature + dspy.Module lenses over a pydantic graph state. The reasoning cycle is the forward() of a single ReasoningEngine module, and the Co-Pilot and Enrich researcher are dspy.ReActV2 tool agents. Because everything is a DSPy module, every layer is optimizable (MIPROv2 / BootstrapFewShot / GEPA), evaluable (dspy.Evaluate), and Refine-validated.
Three tiers
Key facts from DSPy 3.3.0
dspy.ReActV2— native tool calling, reservedsubmittool, parallel tool calls, and prompt-cache reuse. Used for the Co-Pilot and Enrich agents.dspy.Flex— GEPA can discover the engine’s structure itself, as an optional upgrade path for the loop.- Assertions retired.
dspy.Assert,Suggest,constrain, andSoftAssertare removed in 3.x. Validation is done throughdspy.Refine. - One model everywhere:
deepseek-v4-flashaddressed asopenai/<model>via the OpenAI-compatible endpoint (OPENAI_BASE_URL/OPENAI_API_KEY/OPENAI_MODEL). - API conventions: metric on the optimizer constructor,
trainset=keyword-only,module(...)notmodule.forward(...),super().__init__()mandatory. - 3.3.0 breaking changes handled: numpy optional (
dspy[numpy]), GEPA result shapes,dspy.LMErrornormalization.
Layout
qlaw/graph.py— pure pydantic graph state (GraphState,NodeContext,NodeBatch, lens DTOs).apply()is deterministic — the LM never mutates the graph.qlaw/signatures.py— 10 typed signatures (7 lenses + router, termination, chat).qlaw/lenses/— onedspy.Moduleper agent,Refine-validated via the reward functions in_validators.py.qlaw/router.py—LensRouter,Terminator, and the deterministicdefault_lens_for()fallback.qlaw/engine.py—ReasoningEngine+ReasoningLoop+SeedFlow;lens_batch()maps every lens output to aNodeBatch.qlaw/chat.py— multi-turn Qlaw chat: statefulGraphSession,make_chat_tools(), SSE status provider.qlaw/tools.py— pluggablesearchtool (aNotImplementedErrorstub; inject a real backend via DI).qlaw/config.py— one model across all tiers:deepseek_flash()+ startupconfigure_research().qlaw/datasets.py— per-lens and engine trainsets and devsets (30 examples per lens, train/val/test split).qlaw/metrics.py— taxonomy adherence, node validity, conciseness, novelty, coverage, grounding.qlaw/optimize.py— compile pipeline (compile_lens/compile_engine/load_program).qlaw/evaluate.py—dspy.Evaluateharness, writeseval_results.json.qlaw/omni.py— GEPA “omni” meta-optimizer composition (optimize_omni,optimize_parallel, …).qlaw/serve.py— FastAPI + SSE server.scripts/— CLIs:compile.py,evaluate.py,optimize_lenses.py(plus theoptimizewrapper).web/— tldraw frontend (React 19 + Tailwind 4).
Setup
.env. Run LM-hitting commands with uv run --env-file .env. One model is used across all tiers: deepseek-v4-flash via the OpenAI-compatible endpoint. Any OpenAI-compatible model id works via OPENAI_MODEL.
Commands
--strategy omni — explore all engines on a small slice, continue from the validation winner), use the wrapper:
gepa engine’s proposals and evaluation both use the .env model — pass --codex-model to switch to the native Codex agent proposer.
API
POST /seed— prompt → graph with ROOT plus first decomposition layer.POST /engine— one reasoning step:(graph, active_node_id, action)→ expanded graph.POST /chat/stream— SSE: status and tool events, thendonewith the answer plus post-chat graph.GET /config— the active model id (no credentials) for the web client.
/engine outputs use Prediction.toDict() (no model_dump() in DSPy 3.3.0), and max_depth is a constructor argument, not a request field.
Web frontend
The tldraw canvas sits over the engine:web/src/state/graphStore.ts (zustand) holds the canonical GraphState, and web/src/canvas/sync.ts is the only writer of qlaw shapes and arrows. web/src/api/client.ts is the fetch + SSE client.
VITE_API_BASE in web/.env.local if the API port differs from http://localhost:8000.
Testing
The stub-LM strategy needs no API key:tests/helpers.py provides a StubLM that returns canned JSON responses, proving signatures coerce, Refine loops, and ReActV2 submits. Build responses with field_response(...) (ChatAdapter format). Every output field must be present, including reasoning (ChainOfThought adds it).
Learn more
Quickstart
Install with
uv, run the FastAPI service, and open the tldraw frontend.Architecture
The three tiers and the DSPy 3.3.0 primitives that power them.
Lenses
Seven optimizable modules with
Refine-validated output contracts.Engine and router
The reasoning cycle composed as one
dspy.Module.Chat and tools
Multi-turn
ReActV2 Co-Pilot with lenses as tools.API and streaming
FastAPI endpoints, SSE frames, and error mapping.
Optimization and evaluation
Compile pipeline, trainsets, metrics, and bounded GEPA.
Gotchas
DSPy 3.3.0 pitfalls that will cost you time.