Skip to content

Recipes

These recipes show where GroundGuard sits in common agent stacks. The same pattern repeats: record tool facts, generate an answer, then check the answer before release.

Start From A Template

groundguard-init --template github-action
groundguard-init --template openai
groundguard-init --template promptfoo
groundguard-init --template langgraph
groundguard-init --template pydanticai
groundguard-init --template crewai
groundguard-init --template autogen
groundguard-init --template fastapi

Each template writes groundguard.yml, groundguard-ledger.jsonl, answer.txt, and a small integration-specific starter file. Existing files are not overwritten unless you pass --force.

OpenAI Tool Use

Use the OpenAI SDK for the model call, but keep fact registration explicit in your application code:

from groundguard import FactGate

gate = FactGate.from_config("groundguard.yml")
gate.record_tool_result("q3_revenue", "5.2", "billion_usd", source_tool="finance_api")

answer = "Q3 revenue came in at $4.8 billion [fact:q3_revenue]."
report = gate.check(answer, required=["q3_revenue"])
assert not report.passed

See examples/openai_demo/run.py for a runnable deterministic demo and optional live OpenAI SDK path.

LangGraph Node

Put the check in a node after your tool and generation nodes:

from groundguard import FactGate


def groundguard_node(state: dict) -> dict:
    gate = FactGate.from_config("groundguard.yml")
    gate.record_tool_result("q3_revenue", state["q3_revenue"], "billion_usd")
    report = gate.check(state["answer"], required=["q3_revenue"])
    return {**state, "groundguard_report": report, "groundguard_passed": report.passed}

PydanticAI Result Validator

Use GroundGuard in the final result validator or output hook:

from groundguard import FactGate

gate = FactGate.from_config("groundguard.yml")


def validate_agent_result(answer: str) -> str:
    gate.record_tool_result("q3_revenue", "5.2", "billion_usd")
    report = gate.check(answer, required=["q3_revenue"])
    if not report.passed:
        raise ValueError(report.policy_reason or "GroundGuard policy failed")
    return answer

CrewAI Task Callback

Put the gate in a task callback before returning task output:

from groundguard import FactGate

gate = FactGate.from_config("groundguard.yml")


def check_crew_output(output_text: str) -> dict:
    gate.record_tool_result("q3_revenue", "5.2", "billion_usd")
    report = gate.check(output_text, required=["q3_revenue"])
    return {"output": output_text, "groundguard_passed": report.passed}

AutoGen Reply Guard

Use GroundGuard before sending a final reply:

from groundguard import FactGate

gate = FactGate.from_config("groundguard.yml")


def guard_reply(reply: str) -> str:
    gate.record_tool_result("q3_revenue", "5.2", "billion_usd")
    report = gate.check(reply, required=["q3_revenue"])
    if not report.passed:
        return f"GroundGuard blocked this reply: {report.policy_reason}"
    return reply

FastAPI Backend Endpoint

Keep the gate in the backend request path:

from groundguard import FactGate

gate = FactGate.from_config("groundguard.yml")


def check_answer_payload(payload: dict) -> dict:
    gate.record_tool_result("q3_revenue", payload["q3_revenue"], "billion_usd")
    report = gate.check(payload["answer"], required=["q3_revenue"])
    return {
        "passed": report.passed,
        "policy_reason": report.policy_reason,
        "answer": payload["answer"] if report.passed else None,
    }

GitHub Action

For CI checks, generate or commit a ledger JSONL file and answer text file, then run the composite action:

- name: Run GroundGuard
  uses: chasen2041maker/GroundGuard@v0.3.1
  with:
    ledger-jsonl: groundguard-ledger.jsonl
    answer-file: answer.txt
    config: groundguard.yml
    required-facts: q3_revenue
    schema: assertion
    fail-on-policy: "true"

For a PR comment workflow, copy docs/examples/github-actions/pr-comment.yml.

promptfoo

Use GroundGuard as a deterministic assertion alongside promptfoo suites:

from groundguard.integrations.promptfoo import to_promptfoo_assertion

payload = to_promptfoo_assertion(report)

See examples/promptfoo_groundguard/run.py.

DeepEval

Use GroundGuard as a factual component beside broader semantic metrics:

from groundguard.integrations.deepeval import to_deepeval_result

result = to_deepeval_result(report)

See examples/deepeval_groundguard/run.py.

Langfuse, Phoenix, And OpenTelemetry

GroundGuard does not become your tracing platform. Export the report to the platform you already use:

from groundguard.integrations.langfuse import report_to_langfuse_payload
from groundguard.integrations.phoenix import report_to_phoenix_eval
from groundguard.integrations.otel import report_to_otel_events

langfuse_payload = report_to_langfuse_payload(report)
phoenix_eval = report_to_phoenix_eval(report)
otel_events = report_to_otel_events(report)