Agent approval workflows

Human approval for
the actions that matter.

Not every step a bot takes needs a person. A handful do. Klingbar gates that handful with a closed list of verbs, an approval bound by passkey to the exact parameters approved, spend ceilings that refuse rather than warn, and an append-only record of every decision.

Definition

What a human-in-the-loop approval workflow is

A human-in-the-loop approval workflow is a rule that certain actions an agent proposes do not take effect until a named person approves that exact action. Three parts carry the weight: which actions are gated, what the approval is bound to, and where the decision is written down.

Most implementations get the first part and drop the other two. A confirmation dialog that says "run this tool?" gates an action but binds nothing — approve it once and the agent can run something adjacent with the same blessing. A log line records a decision but cannot prove who made it. An approval worth having survives both questions.

The failure mode to design against is not a bot doing something forbidden. It is a person clicking approve forty times a day and stopping reading at the third.

A gate that holds
named action bound to exact parameters single-use written where it can be read back

Drop any one of the four and the gate becomes a habit rather than a control.

Three shapes

The three gate shapes, and what each is for

Refuse if absent. The command is rejected before it can do anything, and the refusal names what is missing. This is the shape for actions where a wait is meaningless: nothing about queueing a credential delivery makes it safer, so it is refused up front rather than parked in a state that could never resolve.

Block, then clear. The command waits, and either an approval from the browser clears it or an operator at the box vetoes it. This is what keeps an unattended machine recoverable: the box retains a veto over its own configuration and its own replacement, even when the console is confident.

Mint and refuse. The first attempt is refused and, in refusing, mints a named approval record. A person answers that record, and the command is re-issued carrying the answer. It suits role-contract edits and metered spend, where the thing being approved is worth reading in full before anyone says yes.

One shape per action, chosen deliberately. A system that mixes them per call is a system where nobody can predict what pressing a button will do.

One mechanism per verb
refuse if absent · credentials, engine accounts block then clear · the chart, the runner's own upgrade mint and refuse · role contracts, metered spend

The mapping is fixed per verb, so the same action always behaves the same way.

Binding

An approval bound to exactly what was approved

Klingbar mints an approval through a passkey ceremony. The result is bound to a hash of the command's parameters and to one freshly-minted command id, and it is single-use. Approving the offboarding of one bot cannot be replayed against another. Approving an edit to a document cannot be spent after that document's base has moved.

That last case is why the base version travels as a parameter rather than as proof. It lands inside the fingerprint the approval covers, so a human's yes is unspendable against a version they never read.

The runner verifies the approval against a key it pinned on first contact. If that pin ever stops matching, Klingbar says so by name and suppresses the ceremony rather than letting you sign something the box has already decided not to honour.

What the signature covers
the verb every parameter, hashed one command id one use

Verified by the runner against a key pinned on first contact — not by the browser that asked.

Spend

A ceiling is a gate too

Budget is the approval question people forget to ask, because it arrives as an invoice rather than as a prompt. In Klingbar a metered command carries a maximum spend as a parameter, which means the ceiling is inside the fingerprint the approval covers: you are not approving "run an evaluation", you are approving "run an evaluation for at most this much".

Roles carry budgets in the org chart above the individual command, so a unit's ceiling binds every role inside it. A bot cannot spend what its role was not given, and the refusal happens before the money moves rather than after.

Two ceilings, both binding
per command · a maximum in the approved parameters per role · a budget declared in the chart

Both refuse. Neither warns and proceeds.

The trail

Append-only, or it is not a trail

Every command transition — queued, delivered, waiting on a person, executing, succeeded, refused, expired — writes an audit row in the same transaction as the status change. Nothing in the console edits or deletes those rows. A record that can be tidied up is a record that has to be argued about later.

The trail is also what makes an unattended failure legible. A command whose runner stopped reporting is marked failed with that reason and that timestamp, rather than sitting green because nothing contradicted it.

Recorded, not summarised
who asked what exactly who approved what the box did

Written with the transition, in the same transaction. Never after the fact.

Slack

Where the decision actually gets made

Approvals only work if they reach a person where that person already is. A Klingbar organization posts through a Slack app your workspace installs, so a bot's work, its questions, and the request for a decision arrive in the same channel as everything else.

The credential that makes that possible never reaches Klingbar in the clear — it is sealed in your browser to your runner's own key. Klingbar shows the state of each integration from what the runner reports, and between issuing a connect command and the runner's next report it says "applied, awaiting the runner's next report" rather than claiming success it cannot see.

Honest states
connected · the runner said so awaiting report · we do not know yet not reported · absent, not zero

A state the control plane cannot verify is never rendered as a green one.

Boundaries

What a browser deliberately cannot do

The console drives a closed vocabulary of thirty-six commands. It is not a shell: the browser never composes an argument list, and there is no verb that carries a key, a token, or a signing secret as a flag. A sealed credential travels as an opaque parameter that only your runner can open.

There is also no verb for creating an approval request. Approval requests are minted by the box, in refusing; only the decision travels back. And a person at the runner's own command line can always veto, which is the property that keeps a machine recoverable when the console is unreachable or simply wrong.

Related reading: an org chart written as code for where approver identity is declared, and self-hosted agents for what does and does not cross the wire.

Frequently asked

What is a human-in-the-loop approval workflow for AI agents?

It is a rule that certain actions an agent proposes do not take effect until a named human approves that exact action. The useful version names which actions are gated, binds the approval to the specific parameters approved, and records the decision where it can be read back later.

Which actions should require approval?

The ones that are expensive to undo: adding or offboarding a worker, changing a role contract, spending real money, and rewriting the organization's own authority file. Reads, filters, and drafts should not be gated — an approval that fires constantly stops being read.

How does Klingbar bind an approval to what was approved?

The approval is minted through a passkey ceremony and bound to a hash of the command's parameters and to a single freshly-minted command id. It is single-use, so an approval of one edit cannot be spent against a different edit, or against the same edit after its base moved.

What happens when nobody is at the browser?

Two of the three gate shapes block rather than refuse, and the runner's own command line can clear or veto them. That is deliberate: it is what keeps an unattended box recoverable when the person who would approve is unreachable.

Where does the approval trail live?

Every command transition writes an append-only audit row in the same transaction as the status change. Nothing in the console edits or deletes those rows, so the trail reads the same later as it did at the moment of the decision.

Decide what needs you, and only that

Klingbar is in early access. Join the waitlist and we'll reach out as capacity opens.

Join waitlist