Skip to content
Agents in Slack

Open source approval gates for agents working in Slack

A Slack approval card only counts if the call is still waiting when it arrives. Kortix is the open-source AI Operating System: a connector call that needs a decision stops before it reaches the provider, posts a card with its parameters, and runs only after a person approves it.

One rule lets a recipient through, the other holds every send

kortix.yaml
policy:  default_mode: riskpolicies:  - match: gmail.send_email    action: always_run    conditions:      - arg: to        match: "*@example.com"  - match: gmail.send_email    action: require_approval

Source: https://kortix.com/docs/connect/connectors

Under risk, a read runs and a write waits, and the glob on to passes one domain while every other recipient waits for a person.

The hold has to happen before the call

A Slack card is a place where a person decides. It cannot stop a call that already left. Kortix holds a connector call before it reaches the provider. When an action matches an Ask rule, the call returns 202 with status: "pending_approval", an approval_url and an execution_id. Nothing ran. The card in the thread then describes a request that is still open, so Approve arrives while the send can still be stopped.

Gmail is one connector among 3,000+ apps in a click, plus MCP, OpenAPI, Postman, GraphQL and raw HTTP. A rule on gmail.send_email applies the same way whether the agent reaches the app through the catalog or through a server the project added from its URL.

What the person deciding gets to read

The connector approval card carries the action, the parameters the connector will receive, and the agent's description of the effect, marked as not verified. Approve and Deny sit on the card. In Slack, Reply… sends a message back to the agent with the decision.

The approval page shows the redacted arguments the provider will receive. The person reads the exact account and payload there.

Some calls carry only ids. For those the agent can add --reason "Weekly report to the team" to describe the effect. The approver sees that line marked as unverified. Kortix never sends the reason to the provider.

One approval covers one exact request

An approval binds the connector, the action, the arguments and the account. A changed argument needs a new approval. A hold on a send to one address does not cover the next address. After an approval, the identical call runs once when it repeats within 15 minutes. There is no session-wide approval. An action that has to run unattended needs an Allow rule, set on purpose.

When a held call lapses

A held call waits 24 hours when the project sets nothing. approvals.ttl moves that window, from 5 minutes to 30 days:

yaml
approvals:  ttl: 4h

An expired call leaves Review → Needs you. Its card shows Expired, and the approval endpoint answers 409 with APPROVAL_EXPIRED. The session does not resume. The agent asks again with a new call.

Who can decide a held call

A project manager or the person who started the session decides. A session started with an API token, from the CLI or from a service account, is decided by project managers only. Anyone else who can open the session sees the call and who decides it, without the buttons. The approval page answers them with 403. Every action is recorded. Reading, exporting and streaming the audit log depend on the plan.

Where the rule lives

policy and policies are keys in the project's kortix.yaml, beside the connectors they govern. The rule belongs to the project and the connector, so every agent reaches the app under the same policy. Kortix evaluates each call in a fixed order, and the first match wins: project-wide rules, the connector's own rules, sensitive: true on the connector, then policy.default_mode. A connector rule cannot override a project-wide rule.

default_mode: allow_all is the default. Approval gates you set. Off until you set them. risk runs reads and holds writes and destructive actions for approval.

A rule can test the arguments of a call. arg takes a dot path such as message.channel, and the match is a glob or a /regex/. A rule holds up to 10 conditions, and all must match. negate: true inverts one. A missing argument never matches, and a malformed condition fails closed.

The rules sit in a file in the project repo, so a change arrives as a diff a reviewer can read. kortix connectors policy set --default risk --apply writes the project rule and applies it. Without --apply the command edits the local kortix.yaml, and kortix ship pushes it.

kortix validate does not check policy or policies. Kortix skips a malformed rule at connector sync and reports it as a sync error, so read the connector settings after a merge.

The file travels with the repo. Run it on Kortix Cloud, in your VPC, or on your own on-prem network. Self-host is free.

What teams ask before they gate a connector

Short answers to the questions that decide whether a gate is worth setting.

How do I approve an AI agent’s tool calls from Slack?
Open the approval card in the thread and select Approve or Deny. Kortix posts the card when a connector call needs a decision, holds the call until someone answers, and passes the decision into the session so the agent continues.
What is the difference between an allow, ask and block policy?
Allow runs the action, Ask holds the call for a person, and Block refuses it. Kortix writes them as always_run, require_approval and block, evaluates the rules in order, and takes the first match.
Can approval rules check the arguments of a call?
Yes. A rule tests a dot path into the arguments, such as to or message.channel, with a glob or a regex, and every one of its up to 10 conditions must hold. A missing argument never matches the pattern.
How long does a held tool call wait?
24 hours by default. A project can set approvals.ttl from 5 minutes to 30 days, for example 4h. A call nobody decides expires, the session does not resume, and the agent asks again with a new call.
Who can approve a connector call?
A project manager or the person who started the session. A session started with an API token, such as from the CLI, is decided by project managers only. Everyone else in the session sees the call and who decides it.

Write the rule once, in the repo you own.

Connect Slack, connect the app, and set the gate that holds the call.

Approval gates you set · Self-host is free · 3,000+ apps in a click