> ## Documentation Index
> Fetch the complete documentation index at: https://comis-feature-matrix-channel.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Approvals

> How to require human approval before agents perform high-risk actions

Some actions are too important to let an AI decide alone. Comis lets you
require human approval before agents perform destructive or sensitive
operations. When an agent tries to delete a file, modify a configuration, or
take another high-risk action, execution pauses until you approve or deny the
request.

## How It Works

Here is what happens when an agent triggers the approval workflow:

<Steps>
  <Step title="Agent wants to perform an action">
    Your agent decides it needs to take an action -- for example, deleting a
    file, sending a mass message, or modifying a configuration setting.
  </Step>

  <Step title="Comis classifies the action">
    Every action is automatically classified as read (safe), mutate
    (modifying), or destructive (irreversible). 178 actions across 21
    categories have specific classifications built in. Any action that is not
    registered defaults to "destructive" -- Comis fails closed.
  </Step>

  <Step title="Confirmation is checked">
    If the action's classification requires confirmation (destructive actions
    do by default), the request enters the approval workflow. The confirmation
    policy determines which classifications require human approval.
  </Step>

  <Step title="Execution pauses">
    The agent stops and waits. The pending request surfaces in three places:

    * The **web dashboard** at `/security` (real-time list with one-click
      Approve / Deny buttons)
    * The **JSON-RPC API** via `approvals.list` and `approvals.resolve`
      methods
    * **Channel DM** to the operator (when the agent runs on a chat channel
      and the operator is reachable there)

    The notification includes the action details, the requesting agent, and
    the reason for the action.
  </Step>

  <Step title="You decide">
    Approve the action to let it proceed, or deny it to block it. If you do
    not respond within the timeout period (default: 5 minutes), the action is
    automatically denied. This ensures that unanswered requests never hang
    indefinitely.
  </Step>
</Steps>

## Dual-Cache Behavior

The approval gate keeps two short-lived caches so repeated identical requests
do not flood operators. Both caches are keyed by `(agentId, actionType,
target)`, so a request for `file.delete /tmp/a` is distinct from
`file.delete /tmp/b`.

| Cache              | Default TTL                                 | Behavior                                                                                                                                      |
| ------------------ | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| **Denial cache**   | 60 seconds (`approvals.denialCacheTtlMs`)   | A fresh request that you just denied is **auto-denied** without paging you again. After the TTL expires, the next request pages you normally. |
| **Approval cache** | 30 seconds (`approvals.batchApprovalTtlMs`) | A fresh request that you just approved is **auto-approved** so a retried agent step does not pause. Set to `0` to disable batching entirely.  |

In addition, **batch followers** join an already-pending entry: if 5 sub-tasks
all request `file.delete /var/log/old.log` while you are looking at the first
one, your single Approve resolves all 5.

The pending approval state serializes/restores on daemon restart, so an
in-flight approval survives a `pm2 restart`.

## Worked Example: Deleting a Build Artifact

Walk through what happens when a coding agent named `code-assistant` decides
to delete a stale build artifact.

<Steps>
  <Step title="The agent issues a tool call">
    `code-assistant` calls `file.delete` with `path: ~/.comis/workspace-code-assistant/build/old.tar.gz`.
  </Step>

  <Step title="Action classifier marks it destructive">
    `classifyAction("file.delete")` returns `"destructive"`. The
    `requireForDestructive: true` policy triggers an approval request.
  </Step>

  <Step title="The gate publishes the request">
    The `ApprovalGate` checks both caches; neither has a hit, so it creates
    a pending entry, emits an `approval:requested` event, and parks the tool
    call on a Promise. The agent's tool loop is now blocked.
  </Step>

  <Step title="You see it on the dashboard">
    The web dashboard's Security view shows:

    > **Pending approval** -- agent `code-assistant` wants to run
    > `file.delete` on `build/old.tar.gz`. *Approve / Deny* (4:58 left).
  </Step>

  <Step title="You click Approve">
    The dashboard calls `approvals.resolve` with `approved: true`. The gate
    writes the entry to the **approval cache** (30s TTL), emits an
    `approval:resolved` event, and unblocks the tool call. The agent
    receives the file-delete result and continues.
  </Step>

  <Step title="A retry within 30 seconds is auto-approved">
    If `code-assistant` decides 10 seconds later to also delete
    `build/old.tar.gz` (e.g., because it raced against a sibling agent),
    the gate finds the cache hit and auto-approves -- you do not see a
    second prompt.
  </Step>

  <Step title="At 31+ seconds, normal approval resumes">
    Past 30 seconds the cache entry expires. A new identical request would
    page you again.
  </Step>
</Steps>

## Two Systems Working Together

Comis has two related but distinct configuration areas for action control.
Understanding the difference prevents confusion when setting up your approval
workflow.

<Warning>
  These two systems work together but are configured separately. Make sure you
  understand both before making changes.
</Warning>

### Action Confirmation (the Policy Layer)

Action confirmation determines **which** actions need confirmation based on
their classification. This is the policy layer -- it decides what triggers the
approval process.

```yaml title="~/.comis/config.yaml" theme={null}
security:
  actionConfirmation:
    requireForDestructive: true   # Require confirmation for destructive actions (default: true)
    requireForSensitive: false    # Require for sensitive/mutate actions (default: false)
    autoApprove:                  # Actions to auto-approve (bypass confirmation)
      - "message.send"            # Example: let agents send messages freely
```

By default, destructive actions require confirmation (`requireForDestructive:
true`) but sensitive/mutate actions do not (`requireForSensitive: false`). You
can adjust this to match your risk tolerance.

The `autoApprove` list lets you exempt specific actions from confirmation even
if their classification would normally require it. This is useful for actions
that are technically destructive but routine in your workflow.

### Approval Workflow (the Execution Layer)

The approval workflow controls **how** the approval process works -- including
rules, timeouts, and trust levels. This is the execution layer that handles
the actual approval requests.

```yaml title="~/.comis/config.yaml" theme={null}
approvals:
  enabled: false                  # Enable the approval workflow (default: false)
  defaultMode: auto               # Default mode: auto | require | deny
  defaultTimeoutMs: 300000        # Timeout: 5 minutes (auto-deny)
  rules:
    - actionPattern: "file.delete"
      mode: require               # Always require human approval
      timeoutMs: 300000
      minTrustLevel: verified
```

Action confirmation decides **what** needs approval. The approval workflow
decides **how** that approval happens. Both work together -- enable action
confirmation to flag which actions need it, then configure the approval
workflow to handle the requests.

## Action Classifications

Every action in Comis is classified into one of three levels. This
classification drives the entire confirmation and approval system.

| Classification | Meaning                        | Examples                                           |
| -------------- | ------------------------------ | -------------------------------------------------- |
| Read           | Safe, no side effects          | Viewing files, reading memory, checking status     |
| Mutate         | Modifies something, reversible | Sending messages, writing files, updating settings |
| Destructive    | Irreversible or high-impact    | Deleting files, dropping data, bulk operations     |

The action registry contains **178 registered actions across 21 categories**.
Unknown actions that are not registered default to destructive -- Comis fails
closed. This means new tools and custom actions are automatically treated as
high-risk until they are explicitly classified. The registry is **locked**
after bootstrap so plugins cannot downgrade classifications at runtime.

<Tip>
  For the complete list of all 178 registered actions and their classifications,
  see [Action Classifier Reference](/reference/action-classifier).
</Tip>

## Approval Modes

The approval workflow supports three modes that control how requests are
handled.

* **auto** (default) -- The system decides based on action classification and
  confirmation settings. Most actions proceed automatically; only flagged
  actions pause for approval. This is the recommended mode for most setups.

* **require** -- Always require human approval regardless of classification.
  Use this for high-security environments where every action must be reviewed.

* **deny** -- Always deny the action. Useful for permanently blocking certain
  operations that should never be allowed, such as file deletion in a
  read-only deployment.

You can set a default mode for all actions and then override it for specific
action patterns using rules:

```yaml title="~/.comis/config.yaml" theme={null}
approvals:
  enabled: true
  defaultMode: auto               # Most actions use auto mode
  rules:
    - actionPattern: "file.delete"
      mode: require               # But file deletion always needs approval
    - actionPattern: "config.*"
      mode: require               # And config changes need approval too
```

## Orchestrate Pre-flight

The [`orchestrate`](/agent-tools/orchestrate) tool adds one approval hook of its own. When
the approval workflow is enabled, a run's script is statically scanned for the set of
capabilities its tool calls require, and **one** approval fires on that whole capability
footprint — the exact set, as a single request — **before** the jailed child is spawned.
Approve it once and the run proceeds; deny it and the run is refused before any code runs.

The same pre-flight also **fails fast**: if the script calls a tool needing a capability the
agent does not hold, the run is rejected pre-spawn with a clear, capability-named error — the
model gets a precise "this needs `orch:web`" message instead of a mid-run failure after the
jail has already been built.

<Warning>
  The pre-flight is an **advisory** fail-fast and approval-UX layer — it is **not** the security
  boundary. The authoritative gate is the jailed child's capability socket, which denies any
  capability the agent does not hold by default (deny-by-absence). A script that hides its call
  sites from the static scan — for example, a dynamically-computed method name — simply proceeds
  past the pre-flight and is still denied at the socket. Never rely on the pre-flight to contain
  a capability: grant only the capabilities you intend, and the endpoint enforces them regardless.
</Warning>

## Using the Dashboard

Pending approvals appear in the [Security dashboard](/web-dashboard/security-view).
You can see the action details, the requesting agent, and the context for the
request. Approve or deny with a single click.

The dashboard shows a real-time list of all pending approval requests across
all your agents, with the most recent requests at the top. Expired requests
(those that timed out) are marked as auto-denied.

## Configuration Reference

| Setting                                             | Default  | Description                                                                |
| --------------------------------------------------- | -------- | -------------------------------------------------------------------------- |
| `security.actionConfirmation.requireForDestructive` | `true`   | Require confirmation for destructive actions                               |
| `security.actionConfirmation.requireForSensitive`   | `false`  | Require confirmation for sensitive/mutate actions                          |
| `security.actionConfirmation.autoApprove`           | `[]`     | Actions that bypass confirmation                                           |
| `approvals.enabled`                                 | `false`  | Enable the approval workflow                                               |
| `approvals.defaultMode`                             | `auto`   | Default approval mode (auto, require, deny)                                |
| `approvals.defaultTimeoutMs`                        | `300000` | Timeout in milliseconds (5 minutes, auto-deny)                             |
| `approvals.denialCacheTtlMs`                        | `60000`  | Auto-deny window for repeats of a denied request (60s)                     |
| `approvals.batchApprovalTtlMs`                      | `30000`  | Auto-approve window for repeats of an approved request (30s, `0` disables) |

<Info>
  The `approvals.enabled` default is `false`. You need to explicitly enable the
  approval workflow to start receiving approval requests. Without it, action
  confirmation still classifies actions, but no human-in-the-loop step occurs.
</Info>

## Related

<CardGroup cols={2}>
  <Card title="Defense in Depth" icon="shield-halved" href="/security/defense-in-depth">
    How approvals fit into the security layers
  </Card>

  <Card title="Hardening" icon="lock" href="/security/hardening">
    Complete security hardening checklist
  </Card>

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

  <Card title="Action Classifier Reference" icon="file-code" href="/reference/action-classifier">
    Complete action registry
  </Card>
</CardGroup>
