Bridle
Guide

Steps

The atomic primitive. Run one unit of model judgment that produces a typed value.

A step runs one model turn — or as many as it takes — until the model produces a value matching your schema. It is the smallest piece of judgment Bridle exposes.

Signature

from bridle import step

step(
    prompt: str,
    *,
    schema: type[T],
    context: Any = None,
    tools: Sequence[Tool] = (),
    label: str | None = None,
) -> T

It returns a Call typed as T. The annotation lies on purpose — the value resolves on first use, but the type checker treats it as already-the-result, which is what your code wants.

The minimum

Prompt and schema:

from pydantic import BaseModel
from bridle import step

class Brief(BaseModel):
    headline: str
    body: str

brief = step("write a brief about Mars weather", schema=Brief)
print(brief.headline)   # resolves now

The model has no extra context — just the prompt — and produces a Brief.

Pass context

context is anything JSON-serializable. Pass values from earlier steps:

plan = step("draft a plan", schema=Plan, context=topic)
brief = step("write the brief", schema=Brief, context=(topic, plan))

Internally, the context is rendered as JSON and appended to the prompt. Pydantic models, dicts, lists, tuples, and primitive types all work. Custom classes need to be serializable — wrap them in a BaseModel or convert to a dict first.

Add tools

Pass @tool-decorated functions as tools=. The model can call any of them during the step:

from bridle import step, tool

@tool
def search(query: str) -> list[str]:
    """Search the web. Returns up to 10 result URLs."""
    ...

sources = step(
    "gather three sources on Mars weather",
    schema=list[Source],
    tools=[search],
)

The model loops: call a tool, see the result, call another, eventually call the synthetic __bridle_return__ with the value. Bridle handles the loop. See tools for the tool side.

Schema retries

When the model returns invalid arguments to __bridle_return__, Bridle feeds the validation error back as a corrective tool result and lets it try again. The default cap is three attempts; on the fourth, SchemaSatisfactionError raises.

The cap shows up in the trace as retry events with reason: "schema". If you see these regularly, your schema is too tight, your prompt is too vague, or both.

Pitfalls

Forgetting to resolve before returning a non-attribute value.

# WRONG — returns a Call, the caller may not realize it
return step("write the brief", schema=Brief, context=ctx)

Inside an @agent, the returned Call is resolved automatically by the dispatcher. Outside an agent, wrap with bridle.resolve if your caller expects the value:

brief = bridle.resolve(step("write the brief", schema=Brief, context=ctx))

Putting decisions in step instead of branch. A step whose schema is bool runs the same model loop with tools enabled — slower and more expensive than necessary. Use branch for one-shot decisions.

Schemas that require text the model has to generate inside the function call. A Brief with a 2000-token body field is fine. A schema with a single text: str field where the model has to produce 5000 tokens of structured prose inside one tool argument is not. Break the work into a step that produces the structure and a step that produces the prose, or relax the schema.

A complete example

import bridle
from bridle import agent, step, tool
from bridle.models.anthropic import install
from pydantic import BaseModel


class Topic(BaseModel):
    title: str
    angle: str


class Plan(BaseModel):
    topics: list[Topic]


@tool
def trending(category: str) -> list[str]:
    """Return trending topic strings for the category."""
    return ["solar wind", "polar caps", "dust storms"]


@agent(input=str, output=Plan, model="claude-sonnet-4-6")
def planner(category: str) -> Plan:
    return step(
        f"draft three topics under {category}",
        schema=Plan,
        context=category,
        tools=[trending],
    )


install()
plan = bridle.resolve(planner("Mars climate"))
for t in plan.topics:
    print(f"- {t.title}: {t.angle}")

Next

On this page