Human-in-the-loop approvals for agent tool calls

Autonomy is fine until the tool call is `kubectl delete pod checkout-api` in production. Approval puts one named person in that gap, and only for the calls that need it.

The decision happens in the response, not after the damage

Descles inspects the structured tool calls in the model response. A call that policy marks require_approval is replaced with a pending-approval placeholder and an approval is opened, so the runtime receives something it cannot execute. An operator sees the tool, the resource and the arguments the model proposed, then approves once or denies.

Approving opens a grant bound to that exact tool call — the same tool name and the same arguments — and consuming it is single-use. A re-issued call that does not match the approved parameters parks again instead of slipping through on a previous decision.

defaults:
  tools:
    Bash: require_approval        # name it exactly as your runtime declares it
    Write: deny
  arg_tools:
    - tool: terminal
      args:
        command: ["rm -rf*", "kubectl delete*"]
      decision: require_approval

Scoped by argument, not only by tool

The useful question is rarely "may this agent read files" but "may it read this file". Argument-scoped rules match the arguments inside a tool call, with deny beating approval beating allow, so a policy can allow a tool broadly and carve out the paths or commands that are never acceptable.

arg_tools:
  - tool: read_file
    args:
      path: ["**/.env", "**/secrets/**"]
    decision: deny
Argument matching on a shell command string is best-effort: rmdir, chained commands, aliases and escapes all dodge a glob. Denies on structured keys such as path or url are reliable; treat a command deny as a speed bump and use a sandbox for a hard edge.

What an approver sees

Who requested it, which agent and group, the tool, the resource scope, and the arguments — on one decision surface, with the choice to deny or approve once. Denying is recorded as a decision, not a deleted row. Slack approvals are planned; today the decision surface is the console.

Questions

What happens if nobody approves in time?

The call stays held and the runtime is told it needs approval rather than being handed the tool call. The durable pending record and the resume path are what let the agent re-issue the same call later without parking again.

Can an approval be replayed to run a different command?

No. The grant is bound to the parameters of the approved call, so a changed argument is a new decision. Consumption is single-use.

Does approval replace a sandbox?

No, and it is not sold as one. Approval is a decision point for intent; a hard execution boundary belongs in the runtime or an action gateway.

Related

  • AI agent control planeA control plane sits beside the data plane: your agents keep talking to their model providers, and the control plane decides who they are, what they may spend, which tool calls they may make, who reviews the risky ones, and what record survives afterwards.
  • MCP securityAn MCP server turns a model into something that can act. Governance is the layer that decides which of those actions may happen, and leaves evidence behind either way.
  • Claude Code governanceA coding agent with a shell is the most useful and most dangerous agent most teams run. Descles keeps the Anthropic credential off laptops and puts a policy in front of the tool calls it proposes.
  • Documentation — endpoints, provider keys, and the full policy reference.

Try it on one agent: 1,000 governed requests free, no card. Request packs add 25,000 more to the same workspace. Questions: outreach@descles.com. See also terms and privacy.