Skip to content
kiffPublic

About

Open-source Go engine that decides each consequential action an AI agent proposes before it runs: state, permissions, approvals, and per-agent limits. The engine behind KIFF Cards.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

KIFF

KIFF

Decide what an AI agent may do before it does it.

CI Go Reference License: MIT Go version Release

KIFF is an open-source Go engine that decides each consequential action an AI agent proposes, before your system runs it. An agent, a person or a service proposes a named action, such as refunding an order. KIFF checks it against the current state of that order, the actor's permissions, the parameters, any approval the action requires, and how much that actor may still do in total. It returns allowed, approval_required, blocked or invalid, and records the decision in one replayable history. Your executor runs only what was allowed.

The rules live in an operational domain. Events establish state. State determines which named actions are valid. Permissions, approvals and limits determine who may do what, and how much. Execution results return to the same history, so every outcome can be explained and replayed.

KIFF does not replace your databases, your agent framework or your systems of record. It sits in front of the consequential calls into them.

KIFF Cards

On kiff.dev, this engine checks an agent's Card: the authority a business gives one agent. A Card says which actions the agent may take, how much per action and in total over a window, and what happens to a call outside it (it waits for the owner, or it is refused). The owner changes or revokes the Card without changing the agent.

This repository has the parts a Card is built on: named actions, state, approvals, and per-actor limits with a ledger (pkg/kiff/limit). Issuing, sharing and revoking Cards, the owner answering held calls, a shared ledger, and signed receipts are features of the hosted service. The table under Run It Yourself or Hosted says exactly what differs.

Why the Authority Belongs Outside the Agent

Ask where an agent's limits are written down today and the answer is usually a prompt, a config file, or a tool handler. Nobody responsible for the money can read them, every change is a deploy, and every new agent writes its own copy.

KIFF keeps that authority outside the agent, in one domain that every actor proposes against. The agent can be replaced; the rules for what it may do stay. Every actor gets the same answers:

Question KIFF's answer
What happened? Recorded events and execution outcomes
What is true now? State derived from those events
What may happen next? Named actions and valid transitions
Who may do it, and how much? Permissions, approvals, and limits
Why did it happen? One decision and audit history

When Every Agent Carries Its Own Rules

The first agent is usually a feature. The next few need a system.

When three actors join the same process, the common pattern is three backend copies. Each owns an interpretation of state, rules, actions, and a custom path into the same systems. That works in isolation. Together, those copies drift, disagree, and multiply the coordination work.

Without a shared operational domain, each actor builds and maintains its own state, rules, and integrations.

One Domain, Many Actors

The actors and systems do not change. KIFF replaces the repeated domain copies with one operational domain and one validated execution path. Every actor sees the same state, proposes the same named actions, and meets the same authority, approval, and limit rules.

This does not replace your agent framework, HTTP stack, queue, cron job, or systems of record. It evaluates proposed actions against current state before your executor runs.

KIFF provides one domain for events, state, actions, authority, and execution.

Without KIFF With KIFF Practical effect
Each actor carries its own version of state and rules. Events and derived state are shared. Actors stop disagreeing about what is true.
Every new actor builds another operational backend. Actors propose the same named actions. Add agents without rebuilding the operation.
Decisions and limits live in application code, prompts, and tool handlers. One decision point evaluates every proposal. Consistent approvals, limits, and refusals.
Logs are scattered across services. Events, decisions, and results form one history. Replay and explain an operational outcome.

A Concrete Example

One domain, one refund:

order-2 is PAID

  agent → REFUND_ORDER  $999, high-risk
  KIFF  ⏸ HELD — approval required            the executor did NOT run
  human → approves
  KIFF  ✓ ALLOWED — refund executes → REFUNDED

  agent → REFUND_ORDER  (same call, retried)
  KIFF  ✗ BLOCKED — order is already REFUNDED  refused before money moves again

  replay from events alone → REFUNDED          materialized == replayed

The useful action runs. The risky one waits for a human. The path rebuilds from the event log.

Be clear about that third line, because it is the one most likely to be oversold. Refusing a repeat on an already-refunded order is table stakes: a unique constraint does it, and whatever framework handed your agent the refund tool very likely does it too. It is shown here because it is the boundary reading state, not because it is a reason to adopt one.

The Check No Per-Call Check Can Make

Your agent is probably already bounded. Whatever gave it the refund tool scoped what it may call, from which state, with which parameters — and it is right every time it runs. It runs once per call, so ten correct refunds is ten correct decisions.

a limit: refund-agent may refund €1,100 per calendar day

  agent → AUTO_REFUND  €42     ✓ ALLOWED   €1,058 left
  agent → AUTO_REFUND  €990    ✓ ALLOWED   €68 left
  agent → AUTO_REFUND  €88     ✗ REFUSED   limit_reached

the third is in the right state, with the right permission, valid
parameters, under the approval threshold, and smaller than the two that
just went through. Nothing is wrong with it. The day is spent.

That refusal cannot come from checking one call, because no single call can see the other two. pkg/kiff/limit holds the ledger that can. It is the same check behind a KIFF Card.

rt, err := runtime.New(runtime.Config{
    Domain: &definition,
    Limits: runtime.StaticLimits{{
        ID:      "refund-agent-daily",
        Subject: "refund-agent",
        Actions: []string{"AUTO_REFUND"},
        Aggregates: []limit.Aggregate{{
            Quantity: limit.Quantity{Parameter: "amount"},
            Max:      110000, // minor units
            Window:   limit.WindowCalendarDay,
        }},
    }},
    LimitLedger: limit.NewMemoryLedger(),
})

Four properties are worth knowing before you rely on it:

  • A limit constrains; it never confers. An actor with no limit is unaffected, so a first limit cannot break a running system.
  • A revoked limit refuses. It does not vanish and leave the actor unbounded. The obvious implementation filters to the limits in force and reads the empty set as "nothing applies, so allow" — which makes revoking a limit the act that removes the bound.
  • An unreadable ledger refuses. Allowing on an unknown balance is the thing a limit exists to prevent.
  • MemoryLedger is correct for one process, and only that. Two replicas each hold their own ledger and each enforces the full ceiling, so the real total is the sum. Implement limit.Ledger against shared storage when you run more than one — a bound on a sequence has to live where the whole sequence is visible.

Run the live tour:

go run ./cmd/kiff-tour

Try It

go install github.com/kiff/kiff/cmd/kiff@latest
kiff new -scenario refund github.com/acme/refunds
cd refunds
go mod tidy
make demo

That creates a runnable refund domain with an Order, a MARK_PAID action, an approval-gated REFUND_ORDER action, a headless HTTP API, and a demo script. Use kiff new <module> without -scenario for a smaller starter project.

One CLI, End to End

The kiff CLI stays with the project from the first domain to a running system:

Workflow What it gives you Commands
Start A runnable KIFF project, with an optional working scenario kiff new
Generate A typed Go domain from a JSON descriptor kiff scaffold
Validate Structural domain checks and static analysis for unguarded Go tools kiff verify, kiff scan
Investigate A readable action, approval, and outcome history for one entity kiff timeline
Publish Authentication and domain contract deployment to KIFF Cloud kiff auth, kiff apply
Operate Views of domains, runtimes, governed usage, and active API keys kiff domains, kiff runtimes, kiff usage, kiff keys

Run kiff help for the full command list or kiff <command> -h for flags.

Connect an Agent

If you already have an agent, you can put its tool calls in front of KIFF without restructuring it. The guard SDK connects KIFF to the pre-execution seam your framework already exposes:

pip install kiff-guard          # or: npm install @kiff/kiff-guard
from kiff_guard import Guard
from kiff_guard.adapters.agno import agno_hook

guard = Guard(mode="observe")   # observe records; enforce refuses before the call runs
agent = Agent(model=..., tools=[refund_order], tool_hooks=[agno_hook(guard)])

Supported agent frameworks

KIFF Guard ships 11 framework adapters across Python and TypeScript:

Agno
Python adapter
LangGraph / LangChain
Python adapter
OpenAI Agents SDK
Python adapter
Google ADK
Python adapter
Pydantic AI
Python adapter
Strands Agents
Python adapter
Microsoft Agent Framework
Python adapter
Hermes
Python adapter
Haystack Agents
Python adapter
LlamaIndex
Python adapter
OpenClaw
TypeScript adapter
Custom / no framework
No adapter required

The adapters are thin integrations at each framework's pre-tool-call boundary; KIFF's decision logic stays in the shared guard core. A custom stack can call that core directly or use plain HTTP without an adapter. See the SDK quickstarts and adapter docs (MIT).

Run It Yourself or Hosted

The framework and guard SDK are MIT. Self-host your operational domain with the postgres store and your own HTTP stack for as long as you like.

If you would rather not operate the state, approvals, receipts, and retention yourself, KIFF Cloud runs them as a hosted control plane with a free tier. The CLI talks to it directly: kiff auth login, then kiff apply to push a domain contract, and kiff domains, kiff runtimes, kiff usage, kiff keys to inspect a tenant. Nothing in this repository requires it.

What the hosted runtime has that this repository does not

Worth stating plainly, because the two are not in lockstep and a gap here is not always a gap there. This repository is the boundary; the hosted runtime was pushed harder to get something real in front of users, and parts of it have not been folded back.

This repository Hosted
Decision boundary, approvals, replay yes same code
Aggregate limits yes (in-process ledger) issued as KIFF Cards: shared ledger, statements, Cards shared by several agents, owner approval of held calls, and a management credential separating who may act from who sets how much
Audit records append-only, no hash, no signature each record's data hashed into a causal chain, the chain signed, an hourly root committed to Base Sepolia (a testnet: signed and verifiable, not a settlement guarantee)
Tenancy, billing, retention not attempted the product
Lease between a decision and the executor open also open

The last row is the one worth reading. Where the hosted runtime is ahead it is said above; where it is not, saying so is the only way this table stays worth consulting.

What the Framework Provides

Capability What KIFF provides
Shared state Events, state transitions, replay, and memory, file, or postgres stores
Named actions Typed parameters, allowed states, required permissions, risk, and explicit executors
Human authority Dynamic approvals, and segregation of duties enforced by default — the actor that requested an approval cannot review it. Reviewer permissions are opt-in per contract, because only the domain knows which permission is sufficient
Reliable execution Validation before side effects and idempotency protection for consequential retries
Explainable history Proposals, decisions, approvals, execution results, and failures as durable protocol data. Records are append-only by construction; tamper-evidence (hash-chained, signed receipts) is a KIFF Cloud feature, not a property of the OSS stores
Open interfaces An optional net/http API and CLI for agents, services, operators, and CI. The API authenticates through a pluggable Authenticator, and the principal it establishes overrides any actor in the request body

Check the Agent Boundary

Use kiff scan . inside a Go agent repository to find explicit agent tools that can reach consequential operations without a recognized decision earlier in the function. Mark a handler with //kiff:tool, pass it to a common tool registration call, or identify it with -tool FunctionName. The initial Go scanner emits terminal, JSON, and SARIF reports and can enforce a CI threshold:

kiff scan .
kiff scan -format sarif -output kiff-scan.sarif -fail-on high .

This is static analysis: a clean result means no supported path was found, not that the application is safe or that every framework-specific registration shape is understood.

For Python agent repositories, use the separate kiff-scan tool instead:

uvx kiff-scan scan .

It also ships a GitHub Action: uses: kiff/kiff-scan@v0.1.1.

Coding Assistant Integrations

These integrations help developers run KIFF's scanners, understand findings, and fix the code. They are development tools, not runtime agent adapters.

Codex
Agent Skill
Claude Code
Plugin / skill
Kiro
Power / Agent Plugin

All three ship the same two skills. See the installation guide for setup and example prompts.

  • kiff-governance — run the scanners, explain findings, and route consequential actions through a real decision boundary. Development workflow.
  • kiff-audit — an adversarial governance audit: extract the guarantees a codebase claims, map its trust boundary, construct and execute attacks against those guarantees, run the language's test and vulnerability tooling, and produce an evidence-backed report with P0/P1 findings and a verdict.

kiff-audit is deliberately not a linter. It treats a claimed guarantee as false until an attack against it has failed, and it reports what it could not establish as not assessable rather than as a pass. The reference audit is a real engagement against this repository in which three of four attacks on the self-approval boundary succeeded.

Documentation

Examples

Cookbook

Use the cookbook when you want to see what KIFF lets a team launch, not just what it can audit after the fact. These recipes model agents proposing useful work while KIFF owns the consequential action boundary.

Who It Is Not For

If your app is simple CRUD, or direct LLM tool calls with no consequential state, KIFF is too much structure — ship something smaller. KIFF earns its keep when agents take consequential actions, what they may do depends on current state and on how much they have already done, some actions need a human sign-off, and someone eventually asks "why did this happen?"

Status

KIFF is at v0.9. The release adds limits — a ceiling on what one actor may do in total, which is the one check a per-call boundary cannot make — plus an adversarial governance audit skill, an authoritative state machine, an authenticated HTTP API, and segregation of duties by default. The core action boundary is complete and adversarially tested: the approved bit cannot be forged from outside the module — including by reflection or unsafe, which a compile-time boundary cannot prevent — a pluggable validator cannot waive a required approval, the state machine is authoritative for validation rather than the caller, the HTTP API authenticates and the principal overrides any actor in the request body, and the actor that requested an approval cannot review it. Those attacks ship as conformance tests that fail the build if the boundary regresses.

Known gaps, stated plainly: audit records are durable and append-only but not tamper-evident in the OSS stores; there is no lease or version check between a decision and the executor, so a decision can in principle be acted on against state that has since moved; and the bundled limit ledger is in-process, so two replicas each enforce the full ceiling and the real total is the sum. The Postgres store is the production reference; the file-backed JSONL stores are for demos and local development.

License

MIT. Use it. Fork it. Ship with it.

About

Open-source Go engine that decides each consequential action an AI agent proposes before it runs: state, permissions, approvals, and per-agent limits. The engine behind KIFF Cards.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages