agentleFS
lauren-frameworklauren-framework/lauren-ai/skills/output-guardrails/SKILL.md

output-guardrails

Skill0 starsChanged 6 months agoMITView on GitHub

Attaches post-generation content filters to agents to redact PII, enforce topic scope, cap response length, or block harmful content before it reaches users. Use when agents generate sensitive content, when compliance requires PII removal, or when responses must stay within a defined topic area.

The file

Files
SKILL.md

Use codemap find "SymbolName" to locate any symbol before reading.

Output Guardrails & Content Filtering

Quick start

# NOTE: future annotations are allowed, but tool signature types must resolve at import time.
from lauren_ai import agent, use_guardrails
from lauren_ai import PIIRedactor, LengthFilter, PromptInjectionFilter

@agent(model="claude-opus-4-6", system="You are a helpful assistant.")
@use_guardrails(
    input=[PromptInjectionFilter()],
    output=[PIIRedactor(), LengthFilter(max_chars=2000)],
)
class SafeAgent: ...

Built-in output guardrails

ClassWhat it does
PIIRedactor()Replaces emails, phone numbers, SSNs, credit cards with [REDACTED]
LengthFilter(max_chars=N)Blocks responses longer than N characters
TopicFilter(allowed_topics=[...])Blocks responses not matching allowed topics
LLMGuardrail(policy="...")Evaluates response with a secondary LLM call

Custom output guardrail

Implement the OutputGuardrail protocol — an async check(response, ctx) method returning a GuardrailDecision:

from lauren_ai import guardrail
from lauren_ai._guardrails._base import GuardrailContext, GuardrailDecision


@guardrail(kind="output")
class TopicScopeGuard:
    """Block responses that don't mention any of the allowed topics."""

    def __init__(self, allowed_topics: list[str]):
        self._topics = allowed_topics

    async def check(self, response: str, ctx: GuardrailContext) -> GuardrailDecision:
        lower = response.lower()
        if any(topic.lower() in lower for topic in self._topics):
            return GuardrailDecision(action="pass", guardrail_name="TopicScopeGuard")
        return GuardrailDecision(
            action="block",
            violation=f"Response is out of scope. Allowed topics: {', '.join(self._topics)}",
            guardrail_name="TopicScopeGuard",
        )

GuardrailDecision fields

FieldTypeDescription
action"pass" | "block" | "modify"What the runner should do
modified_contentstr | NoneReplacement text when action="modify"
violationstr | NoneHuman-readable reason; used as response when action="block"
guardrail_namestrFor logging/debugging

Decorator stacking order

@use_guardrails() sits between @agent() and @use_tools():

@agent(model="claude-opus-4-6")   # outermost
@use_guardrails(
    input=[PromptInjectionFilter()],
    output=[PIIRedactor()],
)
@use_tools(my_tool)                # innermost
class MyAgent: ...

How output guardrails execute

  1. LLM generates a response.
  2. Runner calls each output guardrail in order.
  3. First non-"pass" decision wins:
    • "modify" → modified_content replaces the response in memory and in the returned AgentResponse.content.
    • "block" → violation text becomes the response; loop ends.
  4. Clean responses pass through unchanged.

Streaming note

In streaming mode (run_stream), all chunks are yielded to the caller first (real-time), then guardrails run on the fully assembled text. If a guardrail fires, a sentinel CompletionChunk(guardrail_override="...") is appended to the stream — the frontend should replace the displayed content with this value.

Pitfalls

  • PIIRedactor uses regex patterns — it will miss novel PII formats. For GDPR compliance, add a secondary NER-based check.
  • TopicFilter without embed_fn uses keyword matching — pass an embed_fn for semantic similarity in production.
  • Output guardrails run after the LLM call — they prevent harmful content from reaching users but do not save tokens. For cost savings, use input guardrails to prevent unnecessary completions.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.