# 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
```bash
cargo add guardflow
```
## Usage
```rust,ignore
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:
```rust,ignore
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`](https://crates.io/crates/jsonschema) crate). Implement `Validator` for your own checks.
## graph-flow integration
With the `graphflow` feature, `GuardedTask<T>` wraps any [`graph_flow::Task`](https://crates.io/crates/graph-flow) and re-runs it until the response passes, or gives up after `max_attempts`:
```rust,ignore
use guardflow::graphflow::GuardedTask;
let guarded = GuardedTask::new(my_task, guard).with_max_attempts(3);
```
Works with [`graphflow-stream`](https://crates.io/crates/graphflow-stream) — wrap a task in `GuardedTask` before passing it to `spawn_task`/`spawn_graph`.
## Benchmarks
`cargo bench` ([`benches/overhead.rs`](benches/overhead.rs)):
| `Guard::check`, 1 validator | ~27 ns |
| `Guard::check`, 5 validators (incl. `NoPii`) | ~1.2 µs |
## License
MIT