Docs Frameworks
Microsoft Agent Framework
Status: verified. The adapter ships in
kiff-guard and passes the
conformance suite. The seam was verified against the real
agent-framework-core package.
Shape: middleware (async). A FunctionMiddleware wraps the tool
call: await call_next() runs the tool, or set context.result and
skip call_next to block. The guard decides first and only runs the
tool when allowed. See how the guard works.
Install
pip install "git+https://github.com/kiffhq/kiff-guard.git#subdirectory=packages/python/kiff-guard"
# plus Microsoft Agent Framework, the framework you're guarding:
pip install agent-framework-core
Observe — audit with zero config
from agent_framework import Agent
from kiff_guard import Guard
from kiff_guard.adapters.microsoft_agent_framework import kiff_guard_middleware
guard = Guard(mode="observe") # no client, no tenant needed
agent = Agent(
client=...,
name="assistant",
tools=[refund_order, send_email],
middleware=[kiff_guard_middleware(guard)],
)
Run the agent as usual, then read the trail:
for r in guard.receipts:
print(r.state, r.tool, r.outcome)
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. Only the guard changes:
from kiff_guard import Guard, HTTPClient, ToolMap
from agent_framework import Agent
from kiff_guard.adapters.microsoft_agent_framework import kiff_guard_middleware
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(client=..., name="assistant", tools=[refund_order],
middleware=[kiff_guard_middleware(guard)])
In enforce mode a withheld decision sets context.result to the reason
and skips call_next, so the tool never runs. An allowed decision
awaits call_next and the tool runs. On a transport error the guard
fails closed (blocks) by default.
The seam (verified)
A FunctionMiddleware.process(self, context, call_next) fires before a
tool runs; context.function.name + context.arguments carry the call.
Awaiting call_next() runs the tool; setting context.result and
skipping call_next blocks it. Attached via Agent(middleware=[...]).
Links
- Adapter code:
kiff_guard/adapters/microsoft_agent_framework.py - Microsoft Agent Framework docs: learn.microsoft.com/agent-framework (Middleware → Function middleware)