> ## Documentation Index
> Fetch the complete documentation index at: https://comis-fix-skill-import-vetting-gate.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Approvals

> Human approval on execution paths that explicitly use the approval gate

Comis can pause selected agent actions for an operator decision. The approval
workflow is disabled by default. Set `approvals.enabled: true` to wire the
`ApprovalGate` into the execution paths that support it.

<Warning>
  The approval gate is not a universal interceptor. It protects only code paths
  that explicitly call `ApprovalGate.requestApproval()`. Enabling approvals does
  not automatically wrap every tool, RPC method, or action classification.
</Warning>

## Guarded Paths

The current runtime calls the approval gate from selected paths, including:

* gated agent, provider, skill, token, session, MCP, and channel management
  actions;
* memory deletion and flush;
* channel configuration;
* pipeline execution and save;
* the `orchestrate` capability-footprint pre-flight;
* install-detour overrides in `exec` soft-stop mode; and
* terminal session creation for allowlist entries with `approveOnCreate`.

Review the implementation of the exact tool path you expose. Other operations
may use a model-facing confirmation handshake, a capability check, a trust
gate, or no approval mechanism at all.

## Request Lifecycle

When a guarded path receives an `ApprovalGate` and calls it:

<Steps>
  <Step title="The path creates a request">
    The caller supplies the action identifier, tool name, sanitized parameters,
    agent identity, session key, and trust level.
  </Step>

  <Step title="The gate checks short-lived caches">
    A matching recent approval resolves immediately as approved. A matching
    recent denial resolves immediately as denied. Concurrent identical requests
    join the existing pending request.
  </Step>

  <Step title="Execution pauses">
    On a cache miss, the gate creates a pending request and the guarded call
    awaits its resolution. The request is available in the Security dashboard,
    through the admin approval RPC methods, and through configured channel
    approval interactions.
  </Step>

  <Step title="An operator resolves the request">
    Approval lets the guarded call continue. Denial blocks it. If no operator
    responds before `approvals.defaultTimeoutMs`, the gate denies the request.
  </Step>
</Steps>

The relevant admin RPC methods are:

* `admin.approval.pending`
* `admin.approval.resolve`
* `admin.approval.resolveAll`
* `admin.approval.clearDenialCache`

## Worked Example: Deleting Stored Memory

`memory_manage` has an explicit approval-gate call for its `delete` action.

<Steps>
  <Step title="The agent calls memory_manage">
    The tool validates the delete request and, when an approval gate is wired,
    submits action `memory.delete` before calling the memory RPC.
  </Step>

  <Step title="The gate creates a pending request">
    On a cache miss, the tool awaits the operator's decision. No memory is
    deleted while that Promise is pending.
  </Step>

  <Step title="The operator approves or denies">
    The dashboard or another approval surface resolves the request. Approval
    lets `memory_manage` call `memory.delete`; denial returns a permission error
    without performing the delete.
  </Step>
</Steps>

`classifyAction("memory.delete")` also returns `"destructive"`, but that lookup
does not create this request. The explicit call inside `memory_manage` is what
enforces the human pause.

## Cache Behavior

The approval gate maintains two short-lived caches:

| Cache          | Default TTL | Behavior                                                                                                                    |
| -------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------- |
| Denial cache   | `60000` ms  | A repeated request after an explicit denial is denied without paging the operator again.                                    |
| Approval cache | `30000` ms  | A repeated request after an explicit approval is approved without another prompt. Set the TTL to `0` to disable this cache. |

Both cache matching and pending-request batching use `sessionKey` plus the
action string. Parameters and target values are not part of that key.

<Warning>
  Approving an action can therefore auto-approve the same action in the same
  session with different parameters during the approval-cache TTL. Keep the TTL
  short, or set `approvals.batchApprovalTtlMs: 0` when each target needs a
  separate operator decision.
</Warning>

Pending requests and unexpired approval-cache entries are serialized for a
managed daemon restart and restored when the daemon starts again.

## Classification and Approval Are Separate

The action classifier and the approval gate are independent mechanisms:

* `classifyAction()` returns `read`, `mutate`, or `destructive` for an action
  identifier. Unknown identifiers return `destructive`.
* `requiresConfirmation()` returns a boolean based on that classification.
* Neither function creates an approval request or pauses execution.
* `ApprovalGate.requestApproval()` creates the operator decision point, but
  only callers that invoke it are guarded.

Some tools use a separate `_confirmed` or `requiresConfirmation` handshake with
the model. That handshake is not the operator-backed `ApprovalGate` workflow.

## Configuration Semantics

The settings currently consumed by the runtime approval gate are:

| Setting                        | Default  | Runtime effect                                         |
| ------------------------------ | -------- | ------------------------------------------------------ |
| `approvals.enabled`            | `false`  | Wires the gate into supported execution paths.         |
| `approvals.defaultTimeoutMs`   | `300000` | Sets the pending request timeout.                      |
| `approvals.denialCacheTtlMs`   | `60000`  | Sets the explicit-denial cache TTL.                    |
| `approvals.batchApprovalTtlMs` | `30000`  | Sets the explicit-approval cache TTL; `0` disables it. |

The schema also accepts `approvals.defaultMode`, `approvals.rules`, and
`security.actionConfirmation`. There is currently no general execution rule
evaluator that applies those values across tools or forwards classified actions
to the approval gate. Do not rely on those fields to guard an action unless the
specific execution path documents and implements their use.

```yaml title="~/.comis/config.yaml" theme={}
approvals:
  enabled: true
  defaultTimeoutMs: 300000
  denialCacheTtlMs: 60000
  batchApprovalTtlMs: 0
```

After enabling approvals, test each agent, tool, and channel path that matters
to your deployment. A pending request proves that the specific path reached
the operator-backed gate.

## Orchestrate Pre-flight

When approvals are enabled, `orchestrate` statically extracts the capability
footprint of a script and submits one approval request before spawning the
jailed child. Approval covers that exact extracted capability set.

The pre-flight is an approval and fail-fast layer, not the security boundary.
The jailed child's capability socket remains authoritative and denies missing
capabilities even when static extraction cannot see a dynamically constructed
tool call.

<CardGroup cols={2}>
  <Card title="Defense in Depth" icon="shield-halved" href="/security/defense-in-depth">
    Place approvals within the broader security architecture
  </Card>

  <Card title="Hardening" icon="lock" href="/security/hardening">
    Review the deployment hardening checklist
  </Card>

  <Card title="Security Dashboard" icon="desktop" href="/web-dashboard/security-view">
    Resolve pending requests in the web UI
  </Card>

  <Card title="Action Classifier Reference" icon="file-code" href="/reference/action-classifier">
    Inspect registered action risk levels
  </Card>
</CardGroup>
