/sgr
Design and implement Schema-Guided Reasoning (SGR) pipelines. Translate domain expert mental checklists into structured reasoning schemas for LLMs.
Source: Rinat Abdullin — Schema-Guided Reasoning
Core Principle
SGR = guide LLM reasoning through predefined steps via constrained decoding. Instead of free-form text → enforce a schema that defines what steps, in which order, where to focus attention.
Domain expert mental checklist → Pydantic/Zod schema → Constrained decoding → Deterministic dispatch
When to Use
- Designing agent tool dispatch (NextStep pattern)
- Building structured analysis pipelines (compliance, code review, evaluation)
- Replacing prompt chains with single structured call
- Any place where LLM output must be parseable and actionable
Steps
Parse task from $ARGUMENTS:
- If "audit": scan project for existing Pydantic/Zod schemas, evaluate against SGR patterns
- If task description: design SGR pipeline from scratch
- If empty: ask "What domain/task should the SGR pipeline handle?"
Identify the reasoning cascade — interview the domain:
- What decisions does a human expert make? In what order?
- What information does each step need from previous steps?
- Where does the expert need to "look before deciding"?
- What are the possible actions at the end?
This is the critical step. SGR quality = how well you translate the expert's mental checklist.
Design the schema following SGR patterns:
The NextStep Pattern (agent loop)
class NextStep(BaseModel):
current_state: str # thinking space
plan_remaining_steps: list[str] # 1-5 steps, only first used
task_completed: bool # routing gate
function: Union[Tool1, Tool2, ..., ReportCompletion] = Field(
..., description="execute first remaining step"
)
The Analysis Cascade Pattern (single-shot)
class Analysis(BaseModel):
preliminary: str # initial assessment
classification: Literal["a", "b", "c"] # force categorization
evidence: list[str] # cite sources
gaps: list[GapItem] # structured findings
verdict: Literal["pass", "partial", "fail"] # final decision
reasoning_for_verdict: str # explain after deciding
The Tool Dispatch Pattern
class SendEmail(BaseModel):
tool: Literal["send_email"] # discriminator
recipient: str
subject: str
body: str
class SearchDB(BaseModel):
tool: Literal["search_db"]
query: str
# Union with Literal discriminator = deterministic routing
Action = Union[SendEmail, SearchDB, ReportDone]
Apply SGR design rules (from references/sgr-rules.md):
- Cascade order matters — put analysis before decision, evidence before verdict
- Constrain enums —
Literal["pass", "fail"] not str
- Limit lists —
Annotated[list[str], MinLen(1), MaxLen(5)]
- Discriminated unions —
tool: Literal["name"] for routing
- Verification after decision — add
reasoning_for_X AFTER the enum field, not before
- One schema per reasoning path — don't mix analysis and action in one model
- Discount > 50% guard —
Annotated[int, Le(50)] — bake constraints into types
Implement the dispatch loop (if agent):
for i in range(MAX_STEPS):
response = client.beta.chat.completions.parse(
model=MODEL,
response_format=NextStep,
messages=log,
)
job = response.choices[0].message.parsed
if isinstance(job.function, ReportCompletion):
break # done
result = dispatch(job.function) # deterministic routing
log.append(assistant_message(job))
log.append(tool_result(result))
Add to project:
- Schemas in
schemas/ or models/ directory
- Dispatch in
dispatch.py or equivalent
- Tests: validate schema parsing, test each tool independently
- Document the reasoning cascade in a comment or docstring
Audit mode (if $ARGUMENTS = "audit"):
- Find all Pydantic BaseModel / Zod z.object in project
- Check: do schemas follow cascade order? Are enums constrained? Are unions discriminated?
- Report: which schemas are SGR-compliant, which need fixes
Output
## SGR Pipeline: {domain}
**Pattern:** {NextStep | Analysis Cascade | Tool Dispatch}
**Schemas:** {N} models
**Tools:** {N} (if agent loop)
### Reasoning Cascade
{step 1} → {step 2} → ... → {decision/action}
### Files
- schemas/{name}.py — {N} models
- dispatch.py — tool routing
- tests/test_{name}.py — validation tests
Key References
references/sgr-rules.md — design rules and anti-patterns
references/sgr-demo.py — complete working example (Abdullin's CRM demo, 304 lines Python)
references/sgr-patterns.md — cascade patterns for 6 domains
references/sgr-full-guide.md — full SGR guide with theory, code, tool calling internals
Libraries & Implementations
Rust
- sgr-agent (crate, v0.6.1) — SGR LLM client + agent framework: structured output, function calling, agent loop, 3 agent variants. Core crate for all Rust SGR agents. Part of rust-code
- openai-oxide — typed Rust client for OpenAI API (SGR at compile time via strong types)
In Rust, SGR is even stronger: #[serde(tag = "tool")] gives discriminated union dispatch at zero runtime cost. Enum variants = tools, serde deserialization = constrained decoding.
Python
- sgr-agent-core (1K+ stars) — SGR agentic system design framework by neuraldeep community. Reference Python implementation
- Abdullin's demo in
references/sgr-demo.py — minimal standalone example (304 lines, CRM agent)
Common Issues
Schema too flat
Cause: Tried to put everything in one model.
Fix: Split into analysis model + action model. Cascade, don't flatten.
LLM ignores enum constraints
Cause: Model not supporting constrained decoding, or wrong API.
Fix: Use response_format=Schema (OpenAI), tools with schema (Anthropic). Check references/sgr-rules.md for provider-specific notes.
Agent loops forever
Cause: No task_completed gate or ReportCompletion tool.
Fix: Always include a completion signal in the Union. Cap loop iterations.
1---2name: solo-sgr3description: Use when "design schemas", "structured output", "agent loop", "SGR", "constrained decoding", "tool dispatch", "Pydantic schema for LLM", or need to design a schema-guided reasoning pipeline for an agent or API. Do NOT use for general code review (/review) or planning (/plan).4license: MIT5---67# /sgr89Design and implement Schema-Guided Reasoning (SGR) pipelines. Translate domain expert mental checklists into structured reasoning schemas for LLMs.1011**Source:** [Rinat Abdullin — Schema-Guided Reasoning](https://abdullin.com/schema-guided-reasoning/)1213## Core Principle1415SGR = guide LLM reasoning through predefined steps via constrained decoding. Instead of free-form text → enforce a schema that defines what steps, in which order, where to focus attention.1617```18Domain expert mental checklist → Pydantic/Zod schema → Constrained decoding → Deterministic dispatch19```2021## When to Use2223- Designing agent tool dispatch (NextStep pattern)24- Building structured analysis pipelines (compliance, code review, evaluation)25- Replacing prompt chains with single structured call26- Any place where LLM output must be parseable and actionable2728## Steps29301. **Parse task** from `$ARGUMENTS`:31 - If "audit": scan project for existing Pydantic/Zod schemas, evaluate against SGR patterns32 - If task description: design SGR pipeline from scratch33 - If empty: ask "What domain/task should the SGR pipeline handle?"34352. **Identify the reasoning cascade** — interview the domain:36 - What decisions does a human expert make? In what order?37 - What information does each step need from previous steps?38 - Where does the expert need to "look before deciding"?39 - What are the possible actions at the end?4041 This is the critical step. SGR quality = how well you translate the expert's mental checklist.42433. **Design the schema** following SGR patterns:4445 ### The NextStep Pattern (agent loop)46 ```python47 class NextStep(BaseModel):48 current_state: str # thinking space49 plan_remaining_steps: list[str] # 1-5 steps, only first used50 task_completed: bool # routing gate51 function: Union[Tool1, Tool2, ..., ReportCompletion] = Field(52 ..., description="execute first remaining step"53 )54 ```5556 ### The Analysis Cascade Pattern (single-shot)57 ```python58 class Analysis(BaseModel):59 preliminary: str # initial assessment60 classification: Literal["a", "b", "c"] # force categorization61 evidence: list[str] # cite sources62 gaps: list[GapItem] # structured findings63 verdict: Literal["pass", "partial", "fail"] # final decision64 reasoning_for_verdict: str # explain after deciding65 ```6667 ### The Tool Dispatch Pattern68 ```python69 class SendEmail(BaseModel):70 tool: Literal["send_email"] # discriminator71 recipient: str72 subject: str73 body: str7475 class SearchDB(BaseModel):76 tool: Literal["search_db"]77 query: str7879 # Union with Literal discriminator = deterministic routing80 Action = Union[SendEmail, SearchDB, ReportDone]81 ```82834. **Apply SGR design rules** (from `references/sgr-rules.md`):8485 - **Cascade order matters** — put analysis before decision, evidence before verdict86 - **Constrain enums** — `Literal["pass", "fail"]` not `str`87 - **Limit lists** — `Annotated[list[str], MinLen(1), MaxLen(5)]`88 - **Discriminated unions** — `tool: Literal["name"]` for routing89 - **Verification after decision** — add `reasoning_for_X` AFTER the enum field, not before90 - **One schema per reasoning path** — don't mix analysis and action in one model91 - **Discount > 50% guard** — `Annotated[int, Le(50)]` — bake constraints into types92935. **Implement the dispatch loop** (if agent):9495 ```python96 for i in range(MAX_STEPS):97 response = client.beta.chat.completions.parse(98 model=MODEL,99 response_format=NextStep,100 messages=log,101 )102 job = response.choices[0].message.parsed103104 if isinstance(job.function, ReportCompletion):105 break # done106107 result = dispatch(job.function) # deterministic routing108 log.append(assistant_message(job))109 log.append(tool_result(result))110 ```1111126. **Add to project**:113 - Schemas in `schemas/` or `models/` directory114 - Dispatch in `dispatch.py` or equivalent115 - Tests: validate schema parsing, test each tool independently116 - Document the reasoning cascade in a comment or docstring1171187. **Audit mode** (if `$ARGUMENTS` = "audit"):119 - Find all Pydantic BaseModel / Zod z.object in project120 - Check: do schemas follow cascade order? Are enums constrained? Are unions discriminated?121 - Report: which schemas are SGR-compliant, which need fixes122123## Output124125```126## SGR Pipeline: {domain}127128**Pattern:** {NextStep | Analysis Cascade | Tool Dispatch}129**Schemas:** {N} models130**Tools:** {N} (if agent loop)131132### Reasoning Cascade133{step 1} → {step 2} → ... → {decision/action}134135### Files136- schemas/{name}.py — {N} models137- dispatch.py — tool routing138- tests/test_{name}.py — validation tests139```140141## Key References142143- `references/sgr-rules.md` — design rules and anti-patterns144- `references/sgr-demo.py` — complete working example (Abdullin's CRM demo, 304 lines Python)145- `references/sgr-patterns.md` — cascade patterns for 6 domains146- `references/sgr-full-guide.md` — full SGR guide with theory, code, tool calling internals147148## Libraries & Implementations149150### Rust151- **sgr-agent** (crate, v0.6.1) — SGR LLM client + agent framework: structured output, function calling, agent loop, 3 agent variants. Core crate for all Rust SGR agents. Part of [rust-code](https://github.com/fortunto2/rust-code)152- [openai-oxide](https://github.com/fortunto2/openai-oxide) — typed Rust client for OpenAI API (SGR at compile time via strong types)153154In Rust, SGR is even stronger: `#[serde(tag = "tool")]` gives discriminated union dispatch at zero runtime cost. Enum variants = tools, serde deserialization = constrained decoding.155156### Python157- [sgr-agent-core](https://github.com/vamplabAI/sgr-agent-core) (1K+ stars) — SGR agentic system design framework by neuraldeep community. Reference Python implementation158- Abdullin's demo in `references/sgr-demo.py` — minimal standalone example (304 lines, CRM agent)159160## Common Issues161162### Schema too flat163**Cause:** Tried to put everything in one model.164**Fix:** Split into analysis model + action model. Cascade, don't flatten.165166### LLM ignores enum constraints167**Cause:** Model not supporting constrained decoding, or wrong API.168**Fix:** Use `response_format=Schema` (OpenAI), `tools` with schema (Anthropic). Check `references/sgr-rules.md` for provider-specific notes.169170### Agent loops forever171**Cause:** No `task_completed` gate or `ReportCompletion` tool.172**Fix:** Always include a completion signal in the Union. Cap loop iterations.