flyyy-guard
Block prompt injection anywhere it can enter your agent, using FLYYY's guardrail check.
FLYYY's /api/v1/guardrails/check endpoint, where an LLM judge decides whether the text is an
attack, is called at three points of the agent loop:
| When | What is checked | Catches |
|---|---|---|
| Before the agent starts | the user's prompt | direct injection, jailbreaks, system-prompt extraction, obfuscated or multilingual attacks |
| Before each model call | every new tool result | indirect / RAG / web / email / API / tool-output injection, memory poisoning, cross-agent messages |
| Before each tool runs | the tool name and arguments the model chose | tool-selection and argument manipulation, data exfiltration, goal hijacking |
If any check blocks, the agent stops before the next model or tool step and returns a refusal. Each check is listed in FLYYY → AI Governance → GenAI Governance → your project → Guardrails with its category and subtype, where it was caught, the content's origin and trust, the severity, the affected tool and the action taken.
Attack categories: direct_injection, indirect_injection, tool_output_injection,
memory_poisoning, cross_agent_injection, tool_argument_manipulation, goal_hijacking,
each with subtypes (for example rag_document, api_response, data_exfiltration).
Quickstart (LangChain create_agent)
- Install:
pip install "flyyy-guard[langchain]" # or, in a uv project uv add "flyyy-guard[langchain]"
- Add
FLYYY_URLto the.envthat already holds your project's Langfuse keys. The guard authenticates with those same keys, so no extra key is needed:
If you were given a guardrail key (LANGFUSE_PUBLIC_KEY=pk-lf-... LANGFUSE_SECRET_KEY=sk-lf-... FLYYY_URL=https://<your-flyyy-backend>FLYYY_GUARDRAIL_KEY=fg_...), it is used instead. - Add the middleware where you create the agent:
from flyyy_guard import FlyyyGuardMiddleware agent = create_agent( model=model, tools=tools, system_prompt=system_prompt, checkpointer=checkpointer, middleware=[FlyyyGuardMiddleware()], )
Nothing else changes: agent.invoke(...), your Langfuse CallbackHandler, tools and prompts stay as they are.
The conversation's thread_id is sent as the session id automatically.
When something is blocked, agent.invoke returns normally and the last message is
"Your request was blocked by policy.". Its response_metadata["flyyy_guard"] holds the
category, subtype, severity, where it was caught, the affected tool, the risk score and the
FLYYY request id. A blocked prompt or tool result is replaced in the stored conversation so it
is never sent to the model on later turns; a blocked tool call never runs.
Tell FLYYY what each tool returns, so the dashboard shows where an attack came from:
FlyyyGuardMiddleware(tool_sources={
"search_web": "web_page",
"kb_search": "retrieved_document",
"read_email": "email",
"recall_memory": "memory",
"ask_billing_agent": "agent_message",
})
Upgrading from 0.1.x: tool results and tool calls are now checked by default (one extra check
per tool result and per tool call). Remove FlyyyToolOutputGuardMiddleware, which is deprecated,
or pass check_tool_outputs=False, check_tool_calls=False to keep checking only the prompt.
Any other framework
pip install flyyy-guard
from flyyy_guard import check
decision = check(user_prompt, session_id=session_id)
if not decision.allowed:
return "Your request was blocked by policy."
response = llm.invoke(user_prompt)
check_or_raise(...) does the same but raises PromptBlockedError.
Check other content before your agent acts on it:
from flyyy_guard import FlyyyGuardClient
guard = FlyyyGuardClient()
guard.check(chunk, source="context", origin="retrieved_document", user_task=user_prompt) # RAG chunk
guard.check(memory_text, source="context", origin="memory") # before saving memory
guard.check(api_body, source="tool_output", tool_name="crm_lookup", origin="api_response")
guard.check_tool_call("send_email", {"to": to, "body": body}, user_task=user_prompt) # before running a tool
Options
| Option | Default | Meaning |
|---|---|---|
FlyyyGuardMiddleware(block_message=...) |
"Your request was blocked by policy." |
Reply returned when blocked |
FlyyyGuardMiddleware(unavailable_message=...) |
"The safety check is unavailable right now..." |
Reply when the check itself failed (FLYYY unreachable, timeout, server error) |
FlyyyGuardMiddleware(rejected_message=...) |
"This assistant's safety check is not configured correctly..." |
Reply when FLYYY rejected the agent's keys (wrong, revoked, or from another Langfuse) |
FlyyyGuardMiddleware(check_tool_outputs=...) |
True |
Check every tool result before the model reads it |
FlyyyGuardMiddleware(check_tool_calls=...) |
True |
Check every tool call (name + arguments) before the tool runs |
FlyyyGuardMiddleware(tool_sources={...}) |
none | What each tool returns (web_page, retrieved_document, email, api_response, memory, agent_message, ...) |
FlyyyGuardMiddleware(redact_blocked=False) |
True |
Keep the blocked text in conversation history |
FLYYY_GUARD_FAIL_OPEN=true / fail_open=True |
off | If FLYYY is unreachable, allow instead of block |
FLYYY_GUARD_TIMEOUT=10 / timeout=10 |
10 seconds | How long to wait for FLYYY |
A rejected or revoked guardrail key always blocks, whatever the fail-open setting, so a misconfiguration is noticed instead of silently turning protection off.
Privacy
The guard sends only the text being checked, the session id and, for tool results and tool calls, the tool name and the user's latest message (so FLYYY can tell whether the agent is being steered away from it). It never logs your key or the prompt text. FLYYY stores a short preview of each checked input for the Guardrails view.
Metadata
Release files for flyyy-guard 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| flyyy_guard-0.2.0.tar.gz | 21.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| flyyy_guard-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 34.2 kB
Release files / flyyy_guard-0.2.0.tar.gz
| Download URL | flyyy_guard-0.2.0.tar.gz |
|---|---|
| Size | 21.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
375837e765e3f0c0dfb4a3e3ada829cd6d9e42cfc986a169cd2f82c1c4514f58
|
|
BLAKE2b-256 checksum How to use checksums |
c7d1a585a78f077a62d9199f0a373abbd8515443fd59acb6d9a13792c859092e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logRelease files / flyyy_guard-0.2.0-py3-none-any.whl
| Download URL | flyyy_guard-0.2.0-py3-none-any.whl |
|---|---|
| Size | 13.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2751c6fe467ea73e13694ec6f4d883595053325b5457934f7e7f3de831f2699d
|
|
BLAKE2b-256 checksum How to use checksums |
716760fe71a78aaea0bb9fa48b456d3a6146e07f46780ff66fbc2550cf9abb1d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency log