guardflow 0.1.0

Validators and a retry-until-valid guard for LLM output, in Rust
Documentation

guardflow

Validators and a retry-until-valid guard for LLM output, in Rust — the core pattern behind Python's Guardrails AI, with no Rust equivalent as of 2026.

Install

cargo add guardflow

Usage

use guardflow::{Guard, guard_with_retry};
use guardflow::validators::{NotEmpty, MaxLength, NoPii};

let guard = Guard::new()
    .with(NotEmpty)
    .with(MaxLength(280))
    .with(NoPii::default());

let result = guard.check(&llm_response);
if !result.passed {
    for failure in &result.failures {
        println!("{}: {}", failure.validator, failure.message);
    }
}

Regenerate until it passes, feeding the previous failure back into your prompt:

let text = guard_with_retry(&guard, 3, |last_failure| {
    let prompt = match last_failure {
        Some(f) => format!("Fix this: {:?}. Try again.", f.failures),
        None => "Write a short bio.".to_string(),
    };
    call_llm(prompt)
}).await;

Built-in validators

NotEmpty, MaxLength, MinLength, MatchesRegex, OneOf, ValidJson, NoPii (heuristic regex, not ML), JsonSchema (feature json-schema, via the jsonschema crate). Implement Validator for your own checks.

graph-flow integration

With the graphflow feature, GuardedTask<T> wraps any graph_flow::Task and re-runs it until the response passes, or gives up after max_attempts:

use guardflow::graphflow::GuardedTask;

let guarded = GuardedTask::new(my_task, guard).with_max_attempts(3);

Works with graphflow-stream — wrap a task in GuardedTask before passing it to spawn_task/spawn_graph.

Benchmarks

cargo bench (benches/overhead.rs):

Scenario Time
Guard::check, 1 validator ~27 ns
Guard::check, 5 validators (incl. NoPii) ~1.2 µs

License

MIT