Docs Frameworks
Agno
Status: verified. Agno was the first adapter, and its seam was exercised live against the cloud decide endpoint (kiff-cloud#242).
Shape: middleware. Agno’s tool_hooks hand the guard a continuation
that runs the tool, so the guard runs it via Guard.evaluate(run=...).
See how the guard works for what that means.
Install
pip install "git+https://github.com/kiffhq/kiff-guard.git#subdirectory=packages/python/kiff-guard"
# plus Agno itself, the framework you're guarding:
pip install agno
Observe — audit with zero config
from agno.agent import Agent
from kiff_guard import Guard
from kiff_guard.adapters.agno import agno_hook
guard = Guard(mode="observe") # no client, no tenant needed
agent = Agent(
model=...,
tools=[refund_order, send_email],
tool_hooks=[agno_hook(guard)],
)
Run the agent as usual, then read the trail:
for r in guard.receipts:
print(r.state, r.tool, r.outcome)
agno_hook is one line of real logic — it matches Agno’s hook signature
and calls the guard:
def hook(function_name, func, args):
return guard.evaluate(function_name, args, run=lambda: func(**args))
Activate
Derive a starter domain from what you observed, review it, and activate it in the dashboard:
from kiff_guard import export_yaml
print(export_yaml("my-domain", guard.catalog))
Enforce — govern at runtime
Once you have a tenant and an active domain, point the guard at KIFF and
switch to enforce. Nothing about the agent wiring changes — only the
guard:
from kiff_guard import Guard, HTTPClient, ToolMap
from kiff_guard.adapters.agno import agno_hook
client = HTTPClient(
api_key="kiff_live_...", # mint in the dashboard
tool_map=ToolMap().bind(
"refund_order", action="REFUND_ORDER",
entity_type="Order", entity_arg="order_id"),
)
guard = Guard(client=client, tenant="<tenant>", agent="support", mode="enforce")
agent = Agent(model=..., tools=[refund_order], tool_hooks=[agno_hook(guard)])
In enforce mode a withheld decision raises kiff_guard.Hold; the tool
never runs. The host app maps Hold onto Agno’s human-in-the-loop /
approval flow if it wants the agent to see why.
The seam (verified)
Agno invokes each tool hook as middleware: hook(function_name, func,
args). The hook calls func(**args) to let the tool proceed, or skips
it to block. That maps directly onto the guard’s run continuation.
Links
- Adapter code:
kiff_guard/adapters/agno.py - Seam research: agno.md
- Agno docs: docs.agno.com (Hooks → Tool Hooks)