for teams whose agents are still waiting for a click

Stop manually
approving every
agent action.

Tool access is not authority. A credential lets an agent call refund. It cannot say whether this refund is valid now or how much the agent has already authorized today. KIFF checks the proposed action against live state, permissions, and remaining limits before your code runs it.

Work inside the boundary runs without anyone reading it. Only the exceptions reach a person. Your rules decide, not another model's opinion.

Drop the MIT Guard into an existing agent, or call Cloud over HTTP. KIFF constrains existing authority; it does not grant permission or execute the action.

kiffer, v., to properly enjoy something. That is what a bounded agent is for. How limits work →

what you hand the agent

Issue it an authority. Then stop reading its work.

One agent. The actions it may take, the states they are legal in, and a ceiling for the day. Issued in a click, revoked in a click.

authority · issued active
refund-agent orders · production
may REFUND_ORDER AUTO_REFUND
only when the order is PAID
up to €1,100 per calendar day
until 31 Oct · revocable now
The agent cannot raise this. Only an owner can, and that leaves a record.
why this is not a card
It bounds actions, not spend REFUND_ORDER on a PAID order. A card knows merchant and amount; it cannot know your order is refundable.
Money is one unit The same limit caps three DELETE_CUSTOMER an hour or two deploys a day. It counts consequences, whatever they are.
The holder cannot raise it An agent asking for more room is refused. More room is an owner's decision, and it leaves a record.
What an authority can and cannot express →
the queue nobody planned for

Your agent proposes it. A human still clicks it.

The work moved into a queue: open, skim, agree, click. When every proposal waits for the same manual step, deployment still runs on human throughput.

A tool credential cannot settle whether this action is authorized now. That takes shared state, permissions, approvals, and cumulative limits across the operation.

Review the exceptions. Let the boundary clear the routine. allowed work runs · approval cases wait · limits refuse
the same month, twice
today
agent proposesa person clicks
agent proposesa person clicks
agent proposesa person clicks
agent proposesa person clicks
every one, every month
with KIFF
agent proposesruns
agent proposesruns
agent proposesruns
agent proposesa person
the exception waits for a grant, in the Control Room or your own flow
01 The review is not free Someone accountable reads every proposal, including the ones the rules can already settle.
02 The review stops being one Repeated approvals become muscle memory. The queue looks like control while teaching people to click.
03 So the agent stays caged A per-call check can approve this action. It cannot say what every path has already spent today.
why the checks you have are not enough

Ten correct decisions can still be a wrong day.

Every team building agents arrives at some version of this. Each step is better than the last.

1
Scope the token The agent may call refund, and nothing else. Static. It cannot know this order was already refunded an hour ago.
2
Check state in the agent Read the order first, act only if it is still payable. It lives where the agent lives. Injected text can talk the agent out of its own check.
3
Decide outside the agent KIFF does this A service the agent cannot skip answers before the action runs. Still one call at a time. Every answer is right and the tenth refund is the one that hurt.
4
Count what it has spent KIFF does this One balance across chat, API, email and the agent you add next month, and the holder cannot raise it.

Only the fourth is a fact about the day rather than the call, which is why no per-call check can reproduce it. There is no approve button when it refuses, by design: more room is a raised limit, and that leaves a record of somebody raising it.

what the fourth one has to survive
Two at once Both read the same balance and both proceed. The ledger takes a lock so they cannot.
A retry is not a second refund The same proposal draws once, however many times a flaky connection sends it.
Unreadable is not zero If the balance cannot be read the action is refused, not waved through on an unknown number.
Approval spends it too A refund a person approved still draws on the day. Otherwise the ceiling is advisory.
What a limit is, and what it deliberately is not →
make reality executable

Turn business truth into a system agents can act through.

Model the lifecycle once: what is true now, what actions are possible, and who has authority. Every agent you add next reads the same rule.

1 Establish reality Events produce shared state that every actor can read and replay.
2 Define agency Typed actions declare what is possible, which parameters matter, and who has authority.
3 Record consequences KIFF validates before your application executes, then records the result for everyone who follows.
same pattern · different work
order CARTPAIDFULFILLEDRETURNED
invoice ISSUEDAPPROVEDPAIDRECONCILED
claim OPENEDREVIEWEDAPPROVEDSETTLED
case OPENEDASSIGNEDRESOLVEDCLOSED
peopleagentsservicespartnerssystems
guard connects the stack

Different frameworks. Same reality.

Keep Agno, LangGraph, OpenAI, Google ADK, Strands, n8n, or your own stack. KIFF Guard connects their pre-execution seam to the same operational domain, so state, rules, and history survive every model and framework change.

01, install the guard
your shell
pip install kiff-guard   # or: npm i @kiff/kiff-guard
02, put it in front of the action

Pick your stack. The KIFF side is identical everywhere, the same three-field contract; only the adapter and one attach line change.

agent.py
from kiff_guard import Guard, HTTPClient, ToolMap
from kiff_guard.adapters.agno import agno_hook

tm = ToolMap().bind("refund_order", action="REFUND_ORDER",
                    entity_type="Order", entity_arg="order_id")
guard = Guard(client=HTTPClient(api_key=KEY, tool_map=tm),
              tenant="acme", agent="refunds", mode="enforce")
guard.connect(adapter="agno")

agent = Agent(model=..., tools=[refund_order],
              tool_hooks=[agno_hook(guard)])   # decides before the tool runs
agent.py
from kiff_guard import Guard, HTTPClient, ToolMap
from kiff_guard.adapters.langgraph import kiff_wrap_tool_call

tm = ToolMap().bind("refund_order", action="REFUND_ORDER",
                    entity_type="Order", entity_arg="order_id")
guard = Guard(client=HTTPClient(api_key=KEY, tool_map=tm),
              tenant="acme", agent="refunds", mode="enforce")
guard.connect(adapter="langgraph")

agent = create_agent(model=..., tools=[refund_order],
                     middleware=[kiff_wrap_tool_call(guard)])
agent.py
from kiff_guard import Guard, HTTPClient, ToolMap
from kiff_guard.adapters.openai_agents import kiff_tool_input_guardrail

tm = ToolMap().bind("refund_order", action="REFUND_ORDER",
                    entity_type="Order", entity_arg="order_id")
guard = Guard(client=HTTPClient(api_key=KEY, tool_map=tm),
              tenant="acme", agent="refunds", mode="enforce")
guard.connect(adapter="openai-agents")

@function_tool(tool_input_guardrails=[kiff_tool_input_guardrail(guard)])
def refund_order(order_id: str, amount: int, reason: str): ...
agent.py
from kiff_guard import Guard, HTTPClient, ToolMap
from kiff_guard.adapters.google_adk import kiff_before_tool_callback

tm = ToolMap().bind("refund_order", action="REFUND_ORDER",
                    entity_type="Order", entity_arg="order_id")
guard = Guard(client=HTTPClient(api_key=KEY, tool_map=tm),
              tenant="acme", agent="refunds", mode="enforce")
guard.connect(adapter="google-adk")

agent = Agent(tools=[refund_order],
              before_tool_callback=kiff_before_tool_callback(guard))
agent.py
from kiff_guard import Guard, HTTPClient, ToolMap
from kiff_guard.adapters.pydantic_ai import kiff_before_tool_execute

tm = ToolMap().bind("refund_order", action="REFUND_ORDER",
                    entity_type="Order", entity_arg="order_id")
guard = Guard(client=HTTPClient(api_key=KEY, tool_map=tm),
              tenant="acme", agent="refunds", mode="enforce")
guard.connect(adapter="pydantic-ai")

agent = Agent(model=...,
              before_tool_execute=kiff_before_tool_execute(guard))
agent.py
from kiff_guard import Guard, HTTPClient, ToolMap
from kiff_guard.adapters.strands import kiff_hook_provider

tm = ToolMap().bind("refund_order", action="REFUND_ORDER",
                    entity_type="Order", entity_arg="order_id")
guard = Guard(client=HTTPClient(api_key=KEY, tool_map=tm),
              tenant="acme", agent="refunds", mode="enforce")
guard.connect(adapter="strands")

agent = Agent(model=..., tools=[refund_order],
              hooks=[kiff_hook_provider(guard)])
agent.py
from kiff_guard import Guard, HTTPClient, ToolMap
from kiff_guard.adapters.microsoft_agent_framework import kiff_guard_middleware

tm = ToolMap().bind("refund_order", action="REFUND_ORDER",
                    entity_type="Order", entity_arg="order_id")
guard = Guard(client=HTTPClient(api_key=KEY, tool_map=tm),
              tenant="acme", agent="refunds", mode="enforce")
guard.connect(adapter="ms-agent-framework")

agent = Agent(tools=[refund_order],
              middleware=[kiff_guard_middleware(guard)])
agent.py
from kiff_guard import Guard, HTTPClient, ToolMap
from kiff_guard.adapters.hermes import register_kiff_guard

tm = ToolMap().bind("refund_order", action="REFUND_ORDER",
                    entity_type="Order", entity_arg="order_id")
guard = Guard(client=HTTPClient(api_key=KEY, tool_map=tm),
              tenant="acme", agent="refunds", mode="enforce")
guard.connect(adapter="hermes")

register_kiff_guard(ctx, guard)   # in your Hermes plugin's register()
agent.ts
import { Guard, HTTPClient, ToolMap } from "@kiff/kiff-guard";
import { registerKiffGuard } from "@kiff/kiff-guard/adapters/openclaw";

const tm = new ToolMap().bind("refund_order", {
  action: "REFUND_ORDER", entityType: "Order", entityArg: "order_id" });
const client = new HTTPClient({ apiKey: KEY, toolMap: tm });
const guard = new Guard({ client, tenant: "acme", agent: "refunds", mode: "enforce" });

registerKiffGuard(ctx, guard);   // in your OpenClaw plugin
agent.py
# No adapter needed. Wrap the one function that moves money.
def issue_refund(order, amount):
    d = kiff.decide("REFUND_ORDER", entity=order, amount=amount)
    if not d.allowed:
        return d                         # blocked or held, never execute
    payments.refund(order, amount)       # your code, unchanged
shell
# No SDK. Any language. POST the proposed action; act only on "allowed".
curl -s https://api.kiff.dev/v1/proposals/decide \
  -H "Authorization: Bearer $KIFF_KEY" -H "Content-Type: application/json" \
  -d '{"id":"rd-4471","entity_id":"order-4471","entity_type":"Order",
       "action_name":"REFUND_ORDER","actor_id":"refunds",
       "parameters":{"amount":8400,"reason":"damaged"}}'
# -> {"outcome":"allowed"}   then POST .../execute for a signed receipt

// same three-field contract on every stack: entity + action + parameters -> one verdict.

why the boundary can answer

A limit needs one place to count.

To answer "may this run", the boundary needs the current state and one balance every path draws from. That is what Cloud holds, and why the next agent inherits the rule instead of rebuilding it.

Explore the real KIFF appFully navigable · sample data
Shared domains One lifecycle every actor understands
Current state What is true now, rebuilt from events
Reusable actions The same contract for every agent
Human authority Risky work waits for the right person
One history Every proposal, decision, and result
Build the foundation free. Operate it on Cloud. Cloud meters the operations it runs-never the number of domains, agents, frameworks, or teams that reuse them.
See pricing →
see it in action

Three lines. Your code still runs the action.

One call, before the side effect. KIFF answers; your function returns early or proceeds untouched.

your_app.py
def issue_refund(order, amount):
+ d = kiff.decide("issue_refund", order=order, amount=amount)
+ if not d.allowed:
+ return d # blocked or held, you never execute
payments.refund(order, amount) # your code, unchanged
issue_refund · order 4471 · €42 allowed
Right state, right permission, under the threshold. Runs, and nobody reads it.
issue_refund · order 2287 · €88 refused
Same call, same code path. Refused on the day's authority, and your function never reaches the payment line.
the agent asks for a higher ceiling refused
Its own credential cannot raise its own limit. A limit the agent can raise is not a limit: that is the whole separation.
Run it live, against a real agent →
start with one consequence

Put a boundary around the next action you ship.

Bring one consequential action in your existing agent and application. We model the minimum operational domain around it, connect Guard and Cloud, and leave a shared reality for the next agent.

Thirty minutes, founder-led. Bring a repository or the shape of your setup; you keep the findings whether or not KIFF is the right answer.

boundary review 30 min
01
See the blast radius

Which consequential actions your agents can reach today.

02
Find what cannot refuse

Where nothing on the path is able to say no.

03
Check the evidence

What you could produce if a customer or regulator asked.

04
Decide what changes

A clear view of the gap, whether or not that involves us.

make it yours

Let your coding agent define the operational reality.

The guard connects your runtime. The domain is the contract it decides against, install the KIFF domain skill and your coding agent writes and extends your kiff.yaml against the real grammar: states, approvals, permissions, executors.

install the skill in your agent
Cursor
curl -fsSL https://kiff.dev/skills/kiff-domains.md \
  -o .cursor/rules/kiff-domains.mdc
Instructions for your agent
Set up the KIFF domain skill in this project: run `curl -fsSL https://kiff.dev/skills/kiff-domains.md -o .cursor/rules/kiff-domains.mdc` to add the skill, read it, then help me author a kiff.yaml domain for my riskiest action (states, actions, approvals, permissions, executors) and connect it to KIFF Cloud, validate with POST /v1/me/domain/validate, then PUT /v1/me/domain.
Kiro
mkdir -p .kiro/skills/kiff-domains && curl -fsSL https://kiff.dev/skills/kiff-domains.md \
  -o .kiro/skills/kiff-domains/SKILL.md
Instructions for your agent
Set up the KIFF domain skill in this project: run `mkdir -p .kiro/skills/kiff-domains && curl -fsSL https://kiff.dev/skills/kiff-domains.md -o .kiro/skills/kiff-domains/SKILL.md` to add the skill, read it, then help me author a kiff.yaml domain for my riskiest action (states, actions, approvals, permissions, executors) and connect it to KIFF Cloud, validate with POST /v1/me/domain/validate, then PUT /v1/me/domain.
Codex
curl -fsSL https://kiff.dev/skills/kiff-domains.md >> AGENTS.md
Instructions for your agent
Set up the KIFF domain skill in this project: run `curl -fsSL https://kiff.dev/skills/kiff-domains.md >> AGENTS.md` to add the skill, read it, then help me author a kiff.yaml domain for my riskiest action (states, actions, approvals, permissions, executors) and connect it to KIFF Cloud, validate with POST /v1/me/domain/validate, then PUT /v1/me/domain.
Claude Code
mkdir -p ~/.claude/skills/kiff-domains && curl -fsSL https://kiff.dev/skills/kiff-domains.md \
  -o ~/.claude/skills/kiff-domains/SKILL.md
Instructions for your agent
Set up the KIFF domain skill in this project: run `mkdir -p ~/.claude/skills/kiff-domains && curl -fsSL https://kiff.dev/skills/kiff-domains.md -o ~/.claude/skills/kiff-domains/SKILL.md` to add the skill, read it, then help me author a kiff.yaml domain for my riskiest action (states, actions, approvals, permissions, executors) and connect it to KIFF Cloud, validate with POST /v1/me/domain/validate, then PUT /v1/me/domain.
Copilot
mkdir -p ~/.copilot/skills/kiff-domains && curl -fsSL https://kiff.dev/skills/kiff-domains.md \
  -o ~/.copilot/skills/kiff-domains/SKILL.md
Instructions for your agent
Set up the KIFF domain skill in this project: run `mkdir -p ~/.copilot/skills/kiff-domains && curl -fsSL https://kiff.dev/skills/kiff-domains.md -o ~/.copilot/skills/kiff-domains/SKILL.md` to add the skill, read it, then help me author a kiff.yaml domain for my riskiest action (states, actions, approvals, permissions, executors) and connect it to KIFF Cloud, validate with POST /v1/me/domain/validate, then PUT /v1/me/domain.
Gemini CLI
curl -fsSL https://kiff.dev/skills/kiff-domains.md >> GEMINI.md
Instructions for your agent
Set up the KIFF domain skill in this project: run `curl -fsSL https://kiff.dev/skills/kiff-domains.md >> GEMINI.md` to add the skill, read it, then help me author a kiff.yaml domain for my riskiest action (states, actions, approvals, permissions, executors) and connect it to KIFF Cloud, validate with POST /v1/me/domain/validate, then PUT /v1/me/domain.
Aider
curl -fsSL https://kiff.dev/skills/kiff-domains.md >> AGENTS.md
Instructions for your agent
Set up the KIFF domain skill in this project: run `curl -fsSL https://kiff.dev/skills/kiff-domains.md >> AGENTS.md` to add the skill, read it, then help me author a kiff.yaml domain for my riskiest action (states, actions, approvals, permissions, executors) and connect it to KIFF Cloud, validate with POST /v1/me/domain/validate, then PUT /v1/me/domain.
Amp
curl -fsSL https://kiff.dev/skills/kiff-domains.md >> AGENTS.md
Instructions for your agent
Set up the KIFF domain skill in this project: run `curl -fsSL https://kiff.dev/skills/kiff-domains.md >> AGENTS.md` to add the skill, read it, then help me author a kiff.yaml domain for my riskiest action (states, actions, approvals, permissions, executors) and connect it to KIFF Cloud, validate with POST /v1/me/domain/validate, then PUT /v1/me/domain.
OpenCode
curl -fsSL https://kiff.dev/skills/kiff-domains.md >> AGENTS.md
Instructions for your agent
Set up the KIFF domain skill in this project: run `curl -fsSL https://kiff.dev/skills/kiff-domains.md >> AGENTS.md` to add the skill, read it, then help me author a kiff.yaml domain for my riskiest action (states, actions, approvals, permissions, executors) and connect it to KIFF Cloud, validate with POST /v1/me/domain/validate, then PUT /v1/me/domain.
Windsurf
mkdir -p .windsurf/rules && curl -fsSL https://kiff.dev/skills/kiff-domains.md \
  -o .windsurf/rules/kiff-domains.md
Instructions for your agent
Set up the KIFF domain skill in this project: run `mkdir -p .windsurf/rules && curl -fsSL https://kiff.dev/skills/kiff-domains.md -o .windsurf/rules/kiff-domains.md` to add the skill, read it, then help me author a kiff.yaml domain for my riskiest action (states, actions, approvals, permissions, executors) and connect it to KIFF Cloud, validate with POST /v1/me/domain/validate, then PUT /v1/me/domain.

// then ask your agent: "add an ISSUE_CREDIT action to the refund domain, PAID-only"

where teams put the first one

Two places an agent is already acting.

Not a list of markets. These are the two where the action is already being taken without a person, and the total is countable, euros in the first, how many times in the second. Start with one action in one of them.

Customer operations
Issue refundsApply creditsCancel ordersChange plans
Cloud & infrastructure
Restart servicesScale resourcesRoll back a deployRotate credentials
Start with your first one →
ask AI about KIFF

Open your assistant with a prompt to read llms-full.txt and answer from it.

one action, then the next one

Start with the action you review most.

Run the boundary against your own traffic. See which proposals it would allow, hold, or refuse, then set the ceiling from your evidence. Add the next action to the same operational domain instead of rebuilding state, authority, approvals, and history.

Running on your own infrastructure? The framework is open source →