Approval
Admin-mediated HITL workflows with persistent records and audit trails.
Approval enables a "User Triggers, Admin Authorizes" workflow. When an agent (or team member) hits a protected tool during a run, the run pauses and persists a pending record to your database. Execution only resumes once an admin approves or rejects the request.
Approvals are built on HITL primitives (requires_confirmation, requires_user_input, or external_execution). Your tool must implement at least one.
Approvals work at both the agent and team level. When a member agent in a team calls an @approval tool, the team run pauses with the same flow shown below. See the Team approval example.
Quick start
1from kern.approval import approval2from kern.tools import tool3from kern.db.sqlite import SqliteDb4from kern.agent import Agent56@approval7@tool(requires_confirmation=True)8def delete_user_data(user_id: str) -> str:9 """Permanently delete all data for a user. Requires admin approval."""10 return f"All data for user {user_id} has been deleted."1112db = SqliteDb(db_file="app.db", approvals_table="approvals")13agent = Agent(model=..., tools=[delete_user_data], db=db)When the user asks for something that uses this tool, the run pauses and a pending approval is written to the database. An admin resolves it; then you continue the run.
Approval Types
| Type | Behavior | Use Case |
|---|---|---|
@approval(type="required") or @approval`` | Blocking: Run pauses until an admin reviews and resolves the database record. | Critical actions such as deletion, payments, bulk emails. |
@approval(type="audit") | Non-blocking: Run continues immediately after the HITL interaction is resolved and an audit log is created. | Compliance and activity auditing purposes. |
Blocking
By default, @approval needs HITL approval and requires_confirmation=True is set.
Non-blocking
To enable an audit-style (non-blocking) Human-in-the-Loop flow for persistent audit trails, use @approval(type="audit"). This will create an audit log after the HITL interaction is resolved.
You can use the @tool decorator with log_approval=True to explicitly signal that this tool's execution should be logged in the HITL audit system.
See User Confirmation for details.
Execution Flow
There are three distinct phases in the approval flow:
-
The Pause: When a user triggers an @approval tool, the SDK automatically pauses the run and inserts a pending record into your database.
-
Admin Approval: Admin views the list of pending requests. Then update the record status via the DB provider. Use
expected_status="pending"to prevent race conditions.1db.update_approval(2 approval_id,3 expected_status="pending",4 status="approved", # or "rejected"5 resolved_by="admin_user_id",6 resolved_at=int(time.time()),7 # For requires_user_input or external_execution: pass resolution_data8 # (e.g. values for user input, result for external execution); SDK applies it on continue_run.9) -
Resuming the Run: Continue the run using the
run_id. The SDK verifies the resolution before proceeding. If the record is missing or still pending, continue_run raises a RuntimeError.1run = agent.continue_run(run_id=run.run_id, requirements=run.requirements)
Examples
Blocking approvals
@approval + requires_confirmation: pause, DB record, resolve, continue.
Approval list and resolve
Full lifecycle: pause, list pending, resolve via DB, continue.
Approval with user input
@approval + requires_user_input.
Approval with external execution
@approval + external_execution.
Team approvals
Three patterns: tool on the team, on a member agent, or on both.
Audit approval
@approval(type="audit") + requires_confirmation; no pause, audit record only.
Developer Resources
- Example code: Approvals cookbook.
- Approval reference
- Tool decorator