Skip to main content

Guardrails

Guardrails validate input and output at runtime. They block content that violates policy before it reaches the model or after the model responds. Use them to enforce blocklists, length limits, PII filtering, and custom rules.

Guardrail Interface

Every guardrail implements the Guardrail interface:

type Guardrail interface {
Check(ctx context.Context, content string) Result
}

type Result struct {
Passed bool `json:"passed"`
Reason string `json:"reason,omitempty"`
}
  • Passed: true if the content is acceptable; false to block.
  • Reason: Human-readable explanation when Passed is false.

Engine

The guardrails engine runs rules by position (input or output):

engine := guardrails.NewEngine()
engine.AddRule(guardrails.Rule{
Name: "blocklist",
Position: guardrails.Input,
Guardrail: &guardrails.BlocklistGuardrail{Blocklist: []string{"spam"}},
})
  • CheckInput(ctx, content): Runs all input guardrails. Returns the first failure, or nil.
  • CheckOutput(ctx, content): Runs all output guardrails. Returns the first failure, or nil.

Position

PositionWhen Checked
InputBefore the model receives user content
OutputAfter the model produces a response

Built-in Guardrails

BlocklistGuardrail

Rejects content containing any blocked term (case-insensitive).

g := &guardrails.BlocklistGuardrail{
Blocklist: []string{"password", "secret", "confidential"},
}
result := g.Check(ctx, "Please share your password")
// result.Passed == false, result.Reason == "blocked term: \"password\""

MaxLengthGuardrail

Rejects content exceeding a character limit.

g := &guardrails.MaxLengthGuardrail{MaxChars: 1000}
result := g.Check(ctx, longString)
// result.Passed == false if len(longString) > 1000

Adding via Builder

Use the agent builder to attach guardrails:

a, err := agent.New("my-agent", "My Agent").
WithModel(provider).
AddInputGuardrail("blocklist", &guardrails.BlocklistGuardrail{
Blocklist: []string{"spam", "malware"},
}).
AddOutputGuardrail("max_length", &guardrails.MaxLengthGuardrail{
MaxChars: 4000,
}).
Build()
  • AddInputGuardrail(name, g): Adds input validation.
  • AddOutputGuardrail(name, g): Adds output validation.

Where Guardrails Run

MethodInput CheckedOutput Checked
ChatuserMessage before model callresp.Content after model response
ChatWithSessionuserMessage before model callresp.Content after model response
Runinput["message"] if presentNot applicable

When a guardrail fails, the method returns an error: "input guardrail failed: [input] blocklist: blocked term: \"...\"" or "output guardrail failed: ...".

Custom Guardrails

Implement the Guardrail interface for custom logic:

type PIIGuardrail struct {
Patterns []*regexp.Regexp
}

func (g *PIIGuardrail) Check(_ context.Context, content string) guardrails.Result {
for _, p := range g.Patterns {
if p.MatchString(content) {
return guardrails.Result{
Passed: false,
Reason: fmt.Sprintf("PII detected: %s", p.String()),
}
}
}
return guardrails.Result{Passed: true}
}

Register it:

a.AddInputGuardrail("pii", &PIIGuardrail{
Patterns: []*regexp.Regexp{
regexp.MustCompile(`\b\d{16}\b`), // credit card
regexp.MustCompile(`\b\d{3}-\d{2}-\d{4}\b`), // SSN
},
})

Example: Building a PII Guardrail

package main

import (
"context"
"fmt"
"regexp"

"github.com/spawn08/chronos/engine/guardrails"
"github.com/spawn08/chronos/engine/model"
"github.com/spawn08/chronos/sdk/agent"
)

type PIIGuardrail struct {
Patterns []struct {
Name string
Pattern *regexp.Regexp
}
}

func NewPIIGuardrail() *PIIGuardrail {
return &PIIGuardrail{
Patterns: []struct {
Name string
Pattern *regexp.Regexp
}{
{"credit_card", regexp.MustCompile(`\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b`)},
{"ssn", regexp.MustCompile(`\b\d{3}-\d{2}-\d{4}\b`)},
{"email", regexp.MustCompile(`\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b`)},
},
}
}

func (g *PIIGuardrail) Check(_ context.Context, content string) guardrails.Result {
for _, p := range g.Patterns {
if p.Pattern.MatchString(content) {
return guardrails.Result{
Passed: false,
Reason: fmt.Sprintf("PII pattern matched: %s", p.Name),
}
}
}
return guardrails.Result{Passed: true}
}

func main() {
ctx := context.Background()
provider := model.NewOpenAI("your-api-key")

a, err := agent.New("safe-agent", "Safe Agent").
WithModel(provider).
WithSystemPrompt("You are a helpful assistant.").
AddInputGuardrail("pii", NewPIIGuardrail()).
AddOutputGuardrail("max_length", &guardrails.MaxLengthGuardrail{MaxChars: 2000}).
Build()
if err != nil {
panic(err)
}

resp, err := a.Chat(ctx, "What is the capital of France?")
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(resp.Content)
}