Docs Frameworks

Strands Agents

Status: verified. The adapter ships in kiff-guard and passes the conformance suite. The seam was verified against the real strands-agents package.

Shape: vote (inverted-control). Strands runs the tool itself; its BeforeToolCallEvent hook only votes — set event.cancel_tool to a message to block, leave it unset to allow. 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 Strands, the framework you're guarding:
pip install strands-agents

Observe — audit with zero config

from strands import Agent
from kiff_guard import Guard
from kiff_guard.adapters.strands import kiff_hook_provider

guard = Guard(mode="observe")     # no client, no tenant needed

agent = Agent(
    model=...,
    tools=[refund_order, send_email],
    hooks=[kiff_hook_provider(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 kiff_guard.adapters.strands import kiff_hook_provider

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], hooks=[kiff_hook_provider(guard)])

In enforce mode a withheld decision sets event.cancel_tool to the reason; Strands cancels the call and surfaces the message as a tool result with an error status. An allowed decision leaves the event untouched and the tool runs. On a transport error the guard fails closed (cancels) by default.

The seam (verified)

Strands fires BeforeToolCallEvent before executing a tool; event.tool_use carries the tool name and input, and event.cancel_tool: bool | str blocks the call. The guard registers via a HookProvider attached with Agent(hooks=[...]).