Governance
Handler is built around a simple principle: agents should be powerful, but every action must be tied to a profile, and every profile plays by your rules. Every call is evaluated against your governance rules before it executes.
How It Works
When your agent makes a call through Handler, the request passes through your governance rules before anything happens. Based on those rules, Handler does one of three things:
- Auto-approves the call and executes it immediately.
- Holds the call and notifies you for approval.
- Blocks the call outright and tells the agent why.
This happens in milliseconds. Your agent gets an instant response in all three cases — it never hangs waiting for an unknown outcome.
How you set the rules
Governance is about which actions run automatically, which need your approval, and which are off-limits — not dollar thresholds. Handler classifies every action as a read, a write, or a destructive operation, and you decide what happens to each class. You control this through a few layers, from broad to precise:
1. Templates (risk classes)
The fastest way to set a profile's posture. A template maps the three action classes to an outcome — auto run immediately, approve hold for you, or block refuse. Handler ships three:
- Permissive — everything auto-approves. For fully trusted agents.
- Balanced — reads auto-approve; writes and destructive actions require your approval. The sensible default.
- Restrictive — reads auto-approve; writes and destructive actions are blocked outright.
A profile with no template applied falls back to Balanced behaviour, so a new agent can never silently perform a write without approval.
2. Per-action overrides
Need an exception to the template? Set a specific service or action to allow, approve, or block. A per-action rule wins over the template — for example, keep a Balanced profile but always require approval for handler_communicate sends, or block a single destructive action outright.
3. Service pins
Pin a whole service to require owner approval. A pin is a floor: it forces a hold even when the template would auto-approve — but it can't override an explicit block. Useful for "this agent can use Gmail, but I want to see every send."
4. Approval policies
For conditional routing, create an approval policy. Policies match by scope (action, service, profile, group, or org) and can carry conditions — including a cost condition (cost_above / cost_below) if you do want dollar-based holds — and route the hold to a chosen approver. Policies are how you express "hold anything over $1, and send it to Alice."
5. Spend caps & balance
Independently of the approve/block chain, you can set a monthly spend cap at the org, profile, or instance level, and your org runs on a prepaid balance. Calls fail cleanly when a cap is reached or the balance hits zero — this is a spending guardrail, separate from the action-class rules above.
How a decision is made (precedence)
When a call comes in, Handler resolves it top-down and stops at the first layer that decides:
- Explicit per-action rule — an
allow/approve/blockset on that exact service/action wins over everything. - Template — otherwise the profile's template maps the action's class (read/write/destructive) to auto / approve / block.
- Approval routing — if the outcome is "approve", the profile's routing (see below) decides who gets the hold.
- Approval policies — if routing is left at its default, matching policies (scope-ranked, then by priority) decide.
- Default — with nothing else matching, the call auto-approves.
Two guardrails apply on top: a service pin forces a hold (but never overrides a block), and spend caps / org suspension can fail a call regardless of the above.
Where approvals go
Each profile has an approval routing setting that decides who a held call is sent to:
- Designated member — holds route to a specific person.
- Slack channel — holds post to an allow-listed Slack channel with approve/deny buttons.
- Calling instance — for orchestration: the hold routes to the agent or member that invoked this one.
- Default (unset) — holds fall through to your approval policies.
- None — full trust: the profile auto-approves everything and skips approval policies entirely. Use deliberately — this turns approvals off for that profile.
allow) as you build trust — or tighten sensitive ones with a pin.
Approval Channels
When a call is held for approval, Handler notifies you through your configured channel. You can approve or deny with a single tap — no need to log into a dashboard.
- Dashboard — approve from the Handler web UI with full request details.
- Slack — the request posts to your channel with one-click approve/deny buttons.
- Email — a signed one-click approve/deny link lands in your inbox.
- MCP — orchestrators and master agents approve programmatically via
handler_decide.
Pending request lifetime
Pending requests do not expire automatically. A request can sit in the queue for minutes, hours, or days — it will remain actionable until you explicitly approve or reject it. This is intentional: Handler never makes a call on your behalf without your decision.
What this means for your agent: if your agent calls a tool that gets held and the owner goes offline for a weekend, the agent will continue receiving status: "pending" for that request indefinitely. Well-designed agents should:
- Continue other tasks that don't depend on the held result
- Inform the user if the workflow is blocked waiting for approval
- Optionally check the
request_idviahandler_statusto see if approval arrived
Handler does not currently send a "request expired" signal to agents. If you need time-bounded workflows, reject the request manually from the dashboard and the agent will receive status: "rejected" on its next poll.
Risk classes (templates)
Not sure where to start? Pick the template that matches your comfort level. You can change it, or override individual services, at any time.
| Template | Reads | Writes | Destructive | Best for |
|---|---|---|---|---|
| Permissive | auto | auto | auto | Fully trusted agents on non-sensitive work |
| Balanced | auto | approve | approve | Most production agents — the default |
| Restrictive | auto | block | block | Read-only agents; sensitive environments |
When you create a new agent you pick a template, which sets smart defaults you can customize any time. A profile with no template applied behaves like Balanced, so writes always require approval until you decide otherwise. Want dollar-based holds on top? Add an approval policy with a cost_above condition (see How you set the rules above).
Example Scenario
Here's a real-world walkthrough of governance in action.
Agent makes a call
Your agent decides to send an outbound email:
handler_communicate({
"task": "send",
"to": "ceo@bigcorp.com",
"subject": "Partnership proposal",
"body": "Hi, I'd like to discuss a potential partnership..."
})
Handler evaluates the rules
Sending an email is a write action. This profile is on the Balanced template, so writes require approval — regardless of the tiny $0.005 cost. (A service pin on handler_communicate, or a per-action approve rule, would force the same hold.)
You get notified
Handler holds the request and sends you a Slack message:
To: ceo@bigcorp.com
Subject: Partnership proposal
Approve Deny
You approve
You tap Approve. Handler sends the email and returns the result to your agent. The entire flow — from agent call to your approval to execution — takes seconds.
Agent gets the result
Your agent receives the confirmation and continues its workflow:
{
"status": "executed",
"result": {
"message_id": "msg_a1b2c3",
"sent_to": "ceo@bigcorp.com"
},
"cost": { "charged": 0.005 }
}
What Agents See
Your agent always gets an immediate, structured response. It never hangs or times out. Here are the three possible outcomes:
Executed
The call was auto-approved and completed successfully.
{
"status": "executed",
"result": {
"results": [...],
"query": "AI agent frameworks 2026"
},
"cost": { "charged": 0.005 },
"budget": { "remaining": 9.995 }
}
Pending
The call is held for owner approval. The agent should acknowledge and wait or move on to other tasks.
{
"status": "pending",
"message": "Held for owner approval. Your owner has been notified.",
"request_id": "req_x7y8z9"
}
Blocked
The action isn't permitted — the profile's template blocks that action class (e.g. a write on a Restrictive profile), a rule blocks that service, or a spend cap / zero balance stopped it. The agent should inform the user or try an alternative approach.
{
"status": "blocked",
"message": "Writes are not allowed for this agent (Restrictive template)."
}
pending response means the agent can continue with other work while waiting. A blocked response means the agent should explain the constraint to the user.