for agents & machines

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 blocked decision carries reasons. no_mandate_issued means 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_reached means 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) or enforce (binding); the response carries mode, and an observe decision is marked advisory
Idempotency
proposal id is stable; an idempotent retry is not a second governed operation
propose a consequential action
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"}
  }'
decision (before anything runs)
// 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.