Skip to main content
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.
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.

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:
1

The path creates a request

The caller supplies the action identifier, tool name, sanitized parameters, agent identity, session key, and trust level.
2

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.
3

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.
4

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.
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.
1

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.
2

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.
3

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.
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: Both cache matching and pending-request batching use sessionKey plus the action string. Parameters and target values are not part of that key.
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.
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: 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.
~/.comis/config.yaml
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.

Defense in Depth

Place approvals within the broader security architecture

Hardening

Review the deployment hardening checklist

Security Dashboard

Resolve pending requests in the web UI

Action Classifier Reference

Inspect registered action risk levels