Connect an agent

An agent gets a Card the same way however it is built. What differs is how its actions reach KIFF. Pick the path that matches the agent:

Your agent Path What changes in the agent
Calls tools over MCP (Claude Code, Codex, other MCP clients) The KIFF MCP gateway Its MCP server URL and key. No code.
Runs in your own code, on a framework kiff-guard, below One hook in the agent’s code.
Any code that can make an HTTP call The decision API, below One call before the action.

In every path KIFF decides before the action runs, and only actions that go through KIFF are checked. Give each agent its own key, from its page in KIFF Cloud: that is how KIFF knows which agent is asking, and whose Card to draw on.

Using Claude Code or Codex? Install the KIFF skill and ask it to connect your agent. It walks you through the right path below, drafts the Card, and knows what to do when a call is held.

Connect with kiff-guard

kiff-guard is an open-source (MIT) library that sits in the agent’s own tool-calling loop. Attach it in observe mode, watch what the agent actually does, then switch to enforce so each tool call is checked against the agent’s Card first. The agent keeps doing the work; no rewrite.

1. Install the guard

The guard is an open-source (MIT) package, kiff/kiff-guard, published on PyPI and npm. Install the core plus the adapter for your framework, here, Agno:

pip install "kiff-guard[agno]"

The core has zero required dependencies; each framework adapter pulls its own framework in as an optional extra. For TypeScript (the OpenClaw adapter), npm install @kiff/kiff-guard.

2. Attach it in observe mode

One guard, one hook. observe runs every tool, records a receipt, and learns your action catalog. It needs no client, no tenant, no API key - it never calls KIFF and never blocks a tool.

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)],
)

On a different stack? The hook is the only line that changes. Every framework page shows the same attach with that framework’s one-liner, and How the guard works explains the model behind all of them.

3. Run as usual, and see what it did

Nothing about your agent changes, run it the way you already do. The guard rides along on each tool call and turns each into a receipt.

agent.run("Refund order ord_4821 and email the customer")

for r in guard.receipts:
    print(r.state, r.tool, r.outcome)
# observed refund_order observed
# observed send_email   observed

4. Derive a domain from real traffic

Because the guard learned the catalog while it watched, it hands you a starter KIFF domain drafted from what the agent actually does, so you never face a blank kiff.yaml:

from kiff_guard import export_yaml
print(export_yaml("my-domain", guard.catalog))
# KIFF domain draft for 'my-domain'
# Auto-derived from observed agent traffic (instrument-first).
domain: my-domain
actions:
  - name: refund_order
    parameters: [amount_cents, order_id]
    risk: low            # TODO(human): low | medium | high
    requires_approval: false   # TODO(human)
  - name: send_email
    parameters: [body, to]
    risk: low            # TODO(human): low | medium | high
    requires_approval: false   # TODO(human)

The draft is a starting point, you set the risk, thresholds, and approval rules. KIFF derives the observed action surface; it never invents authority you didn’t declare.

5. Give the agent a key and a Card, then enforce

  1. In KIFF Cloud, open the agent on My agents (or Agents), go to its Keys tab and choose Create a kiff-guard key. The key is bound to this agent and shown once. Put it in the agent process’s environment:
   export KIFF_CLOUD_URL=https://api.kiff.dev
   export KIFF_CLOUD_API_KEY='kiff_live_...'
  1. Give the agent a Card for the actions it should take, from its Cards tab or Issue a card.
  2. Switch the guard to enforce and give it the client that carries the key. KIFF now decides before each tool runs: allowed proceeds, approval_required waits for the owner (see Held calls and approvals), blocked refuses. If KIFF can’t be reached, the guard fails closed.
guard = Guard(mode="enforce", client=client)   # client carries the key

Keep two kinds of credential apart:

  • the agent’s KIFF key only asks KIFF for decisions. It cannot grant itself authority or change its own Card;
  • your provider credentials (the model API, your payments API) stay where they already live. kiff-guard never sends them to KIFF.

To cut the agent off, revoke its key on its Keys tab. Its next call with that key is refused; other agents are untouched.

Call the decision API directly

No framework, or code you’d rather not hook? Immediately before a consequential call, send the proposed action to KIFF and branch on the answer. KIFF returns the decision; your code still runs the action.

import os
import requests

def ask_kiff(*, entity_id, entity_type, action, parameters, actor_id):
    response = requests.post(
        f"{os.environ['KIFF_CLOUD_URL']}/v1/proposals/decide",
        headers={"Authorization": f"Bearer {os.environ['KIFF_CLOUD_API_KEY']}"},
        json={
            "entity_id": entity_id,
            "entity_type": entity_type,
            "action_name": action,
            "actor_id": actor_id,
            "parameters": parameters,
        },
        timeout=5,
    )
    return response.json()

decision = ask_kiff(entity_id=order_id, entity_type="Order", action="ISSUE_REFUND",
                    parameters={"amount": amount}, actor_id="refund-agent")
if decision["outcome"] == "allowed":
    process_refund(order_id, amount)
Outcome Meaning What your code does
allowed State, contract and Card permit it. Run the action.
approval_required The owner must decide first. Hold the action.
blocked State, permissions, parameters or the Card forbid it. Do not run it.
invalid The request or domain configuration is incomplete. Fix the request or domain.
limit_exceeded The account’s Cloud allowance is used up. Do not run; check billing.

Branch on outcome, not only the HTTP status. Where the action draws on a Card, actor_id must be the agent the Card was issued to, and the key must be that agent’s own key: a key issued for another agent is refused, so one agent cannot spend another’s Card.

This governs only the calls you route through it. It proves what KIFF authorized before the call, not that your function completed.

Where to go next

  • Agents that call MCP tools → Use the KIFF MCP gateway.
  • The model behind observe and enforce → How kiff-guard works.
  • Your framework’s hook → pick it from the sidebar; each adapter ships in kiff-guard and passes its conformance suite.
  • What a Card can say → KIFF Cards.

The guard, every adapter, and the conformance suite live in the public MIT repo kiff/kiff-guard.