Docs Frameworks
Haystack Agents
Status: verified. The adapter ships in
kiff-guard and passes the
conformance suite. The seam was verified against the real haystack-ai
package.
Shape: vote (inverted-control). Haystack runs the tool itself; a
ConfirmationStrategy only votes — return a decision with
execute=True to allow, execute=False to block. So the guard uses
observe() / decide_only(), not a run callback. See
how the guard works.
Install
pip install "git+https://github.com/kiffhq/kiff-guard.git#subdirectory=packages/python/kiff-guard"
# plus Haystack, the framework you're guarding:
pip install haystack-ai
Observe — audit with zero config
from haystack.components.agents import Agent
from kiff_guard import Guard
from kiff_guard.adapters.haystack import kiff_confirmation_strategy
guard = Guard(mode="observe") # no client, no tenant needed
agent = Agent(
chat_generator=...,
tools=[refund_order, send_email],
confirmation_strategies={
"refund_order": kiff_confirmation_strategy(guard),
"send_email": kiff_confirmation_strategy(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 haystack.components.agents import Agent
from kiff_guard.adapters.haystack import kiff_confirmation_strategy
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(chat_generator=..., tools=[refund_order],
confirmation_strategies={"refund_order": kiff_confirmation_strategy(guard)})
In enforce mode a withheld decision returns execute=False with the
reason as feedback, so the tool never runs. An allowed decision returns
execute=True and the tool runs. On a transport error the guard fails
closed (blocks) by default.
The seam (verified)
Haystack calls a ConfirmationStrategy.run(*, tool_name,
tool_description, tool_params, tool_call_id, ...) before executing a
tool; it returns a ToolExecutionDecision(execute=bool, feedback=...).
The guard’s strategy is passed via Agent(confirmation_strategies=...).
Links
- Adapter code:
kiff_guard/adapters/haystack.py - Haystack docs: docs.haystack.deepset.ai (Agent → human-in-the-loop)