KIFF for agents
KIFF decides consequential agent actions before they run. An agent (or human, or service) proposes an action; KIFF decides whether it is allowed, against state, permissions, parameters and human approval, before it runs, and records a signed, tamper-evident receipt. Where the action declares requires_authority, the decision also draws on the card issued to that actor, and is refused without one. Your own systems execute the side effect on an allowed decision. KIFF never touches your money or credentials.
Use KIFF when an agent is about to perform a consequential external action that must be evaluated against state, permissions, parameters, or human approval before execution.
Use KIFF when
- An agent can take an action that moves money or changes state (refund, payout, credit, access change).
- The action must be checked against current state and who is allowed, before it runs.
- Some actions should hold for a human, and every decision needs an auditable record.
Don't use KIFF for
- Improving model output, that's model/prompt tooling.
- Filtering model content, that's a guardrail/moderation layer.
- Orchestrating a long workflow, authenticating a human, or brokering API access, workflow engine / IdP / IAM.
Interface
- Base URL
https://api.kiff.dev- Auth
Authorization: Bearer <api_key>(mint in the dashboard)- Decision endpoint
POST /v1/proposals/decide- Execute (mints receipt)
POST /v1/entities/{id}/actions/{name}/execute- Approvals
POST /v1/approvals/{id}/grant→ re-decide- Outcomes
allowed·approval_required·blocked·invalid- Card refusals
- A
blockeddecision carries reasons.no_mandate_issuedmeans nothing has been issued to this actor for this action, and the action declares it needs a card, wiring, not policy: ask an owner to issue one.mandate_limit_reachedmeans the proposed action would exceed the card's remaining authority for this window, which is not the same as the card being empty: a smaller action may still fit. More room is an owner's decision, not something to retry into. - Multi-domain
- route with body
"domain"(decide) or?domain=<slug>(execute/events); empty = default domain - Posture
- each domain runs in
observe(decision advisory, recorded, not enforced) orenforce(binding); the response carriesmode, and an observe decision is markedadvisory - Idempotency
- proposal
idis stable; an idempotent retry is not a second governed operation
curl -s https://api.kiff.dev/v1/proposals/decide \
-H "Authorization: Bearer $KIFF_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"id": "rd-ord_4821",
"entity_id": "ord_4821",
"entity_type": "Order",
"action_name": "REFUND_ORDER",
"actor_id": "support-agent",
"parameters": {"amount": 10000, "reason": "duplicate charge"}
}'// allowed, your code runs the action, then mints a receipt
{"outcome": "allowed"}
// held for a person (action.approval: required), you do NOT execute
{"outcome": "approval_required", "approval": {"id": "apr_..."}}
// refused before anything runs (e.g. the order already left PAID)
{"outcome": "blocked", "reasons": ["state_not_allowed"]}
// malformed proposal (missing parameter, unknown action)
{"outcome": "invalid", "reasons": ["missing_parameter"]}Minimal integration
Point an MCP agent at the KIFF gateway, attach kiff-guard to your agent's tool calls (open-source, MIT, on PyPI and npm), or call the decision endpoint directly from any language. In observe mode the guard derives a starter domain from real traffic; in enforce mode it asks KIFF to decide before each tool runs. In Claude Code or Codex, the KIFF skill connects the agent, drafts its Card and handles held calls; the domain skill authors the domain.
Current status
- Framework: MIT-licensed, Go, self-hostable with zero cloud.
- KIFF Cloud: hosted runtime over HTTP: decisions, approvals, signed receipts, dashboard.
- Honest boundaries: no SOC 2 or EU data residency yet; KIFF keeps only numeric parameters, which limits count, but the agent's free-text reason is stored as written. See security & posture.