How the OpenHuman Approval Gate Handles Interactive vs Background Turns

The OpenHuman approval gate intercepts tool calls in src/openhuman/security/approval/gate.rs and requires explicit user consent for interactive turns, while auto-approving background turns unless the tool schema explicitly demands approval via require_approval_for_medium_risk.

OpenHuman implements a security layer called the approval gate to protect against unauthorized AI agent actions. This system distinguishes between interactive turns initiated by users through the chat interface and background turns executed by scheduled jobs or sub-agents. Understanding how the approval gate processes these two turn types is essential for configuring secure yet efficient automated workflows in the tinyhumansai/openhuman repository.

Where the Approval Gate Intercepts Tool Calls

The approval gate lives in the tool execution path inside the OpenHuman core. When an AI agent decides to invoke a tool, the request passes through ApprovalGate::check in src/openhuman/security/approval/gate.rs before reaching the actual tool implementation.

The gate evaluates three critical factors:

  • The current access tier (e.g., Access::full(), Access::supervised())
  • The risk level of the tool (defined in src/openhuman/tools/registry.rs as Medium, High, etc.)
  • The origin type of the turn (interactive UI vs. background process)

This evaluation determines whether the tool executes immediately, gets parked pending approval, or is denied based on policy.

Interactive Turns: User-Driven Approval Flow

Interactive turns originate from the desktop UI (app/) via CoreRpcClient::run_turn or direct user chat messages. By default, the environment variable OPENHUMAN_APPROVAL_GATE=1 ensures the gate is installed for every interactive session.

Decision Flow for Interactive Turns

When a user-initiated turn triggers a tool call, the gate executes the following sequence:

  1. Risk Classification: The gate checks the tool's risk level against the workspace's access tier permissions in the tool registry.
  2. Parking: If the tool's risk exceeds the tier's allowance, the gate parks the turn and creates a pending approval entry in the SQLite database at src/openhuman/security/approval/store.rs.
  3. UI Prompt: The desktop application renders an ApprovalRequestCard offering four options: Approve Once, Always Approve, Deny, or Ask Later.
  4. Resumption: Once the user decides, the gate resumes the parked turn using gate.pending_for_thread(...).as_deref(), records the decision for auditing, and finally executes the tool.

Interactive turns never bypass required decisions because the user is present to review high-risk actions.

Background Turns: Automated Execution with Policy Override

Background turns are generated by the cron scheduler, sub-agents, or workflow runners without an attached UI. While the gate remains active for these turns, its default policy shifts to auto-approve unless the tool explicitly opts into scrutiny.

Auto-Approval and Deferred Decisions

For background execution, the decision flow differs:

  1. Schema Check: The gate examines the tool's JSON schema for require_approval_for_medium_risk. If this flag is false (the default for background contexts), the call auto-approves regardless of risk level.
  2. Forced Parking: If the tool schema sets require_approval_for_medium_risk = true, the gate parks the turn and inserts a pending approval entry identical to interactive mode.
  3. RPC Fallback: Without a UI, the system relies on the "Ask Later" path. Administrators must resolve parked turns via the RPC endpoints openhuman.approval_list_pending and openhuman.approval_decide defined in src/openhuman/security/approval/rpc.rs.

Background-parked approvals carry a configurable deadline specified in src/openhuman/security/approval/types.rs. If no decision arrives before the deadline expires, the gate treats the request as denied and records a failure in the execution log.

Approving Pending Requests via RPC

When background turns require manual intervention, administrators interact with the approval system through HTTP RPC endpoints:


# List all pending approvals across background jobs

curl -H "Authorization: Bearer $TOKEN" \
     http://localhost:8000/rpc/openhuman.approval_list_pending

# Approve a specific request by audit_id

curl -X POST -H "Authorization: Bearer $TOKEN" \
     -d '{"audit_id":"<audit_id>","decision":"ApproveOnce"}' \
     http://localhost:8000/rpc/openhuman.approval_decide

These endpoints allow automated cleanup scripts or admin dashboards to manage the approval queue for headless workloads.

Persistence and Audit Trail

All pending and final decisions are stored in a per-workspace SQLite file located at <workspace>/approval/approval.db. The store layer in src/openhuman/security/approval/store.rs provides CRUD operations used by both the gate logic and the RPC layer.

Audited decisions are exposed via openhuman.approval_list_recent_decisions, which powers the Approval History panel in the desktop UI. This ensures every tool invocation—whether approved automatically or manually—leaves a forensic trail for security review.

Configuration Options

You can tune the approval gate behavior through environment variables and tool-level flags.

Disabling the Gate Entirely

For testing scenarios, set the environment variable before initializing the core:

std::env::set_var("OPENHUMAN_APPROVAL_GATE", "0");

This bypasses all approval checks and should never be used in production environments handling sensitive data.

Tool-Level Risk Flags

Each tool's definition in src/openhuman/tools/registry.rs can specify:

{
  "name": "send_email",
  "risk_level": "Medium",
  "require_approval_for_medium_risk": true
}

Setting require_approval_for_medium_risk to true forces the approval gate to park the turn even when running in background mode, ensuring critical operations receive human oversight.

Summary

  • Interactive turns always trigger the approval gate for high-risk tools, presenting an ApprovalRequestCard to the user and waiting for explicit consent via gate.pending_for_thread.
  • Background turns auto-approve by default unless the tool schema explicitly sets require_approval_for_medium_risk = true, falling back to RPC endpoints for deferred decisions.
  • All decisions are persisted in <workspace>/approval/approval.db via store.rs and exposed through openhuman.approval_list_recent_decisions for auditing.
  • The gate can be disabled via OPENHUMAN_APPROVAL_GATE=0 for testing, but tool-level flags provide granular control over which operations require oversight.

Frequently Asked Questions

How does the approval gate distinguish between interactive and background turns?

The gate inspects the turn's origin type passed through the execution context. Interactive turns originate from CoreRpcClient::run_turn in the UI layer, while background turns come from the cron scheduler or sub-agent workers. This origin metadata determines whether the gate presents a UI card or applies the background auto-approval policy.

What happens when a background turn requests approval but no administrator is available?

If a background turn parks for approval and the configurable deadline (defined in src/openhuman/security/approval/types.rs) expires without a decision via openhuman.approval_decide, the gate automatically treats the request as denied. The turn fails with an audit entry recording the timeout, preventing workflows from hanging indefinitely.

Can I require approval for specific tools only in background mode?

Yes. In src/openhuman/tools/registry.rs, set the tool schema flag require_approval_for_medium_risk = true. This forces the approval gate to park the turn even during background execution, creating a pending entry that must be resolved through the RPC endpoints rather than auto-approving.

Where does the approval gate store pending decisions?

The gate persists all pending and completed decisions to a SQLite database at <workspace>/approval/approval.db. The src/openhuman/security/approval/store.rs module handles all database operations, while src/openhuman/security/approval/rpc.rs exposes query endpoints for external tools to inspect the approval queue.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →