teaflask

AI agent permissions: allow, ask or deny, and the yes budget

Ragav Sachdeva10 Oct 2026

Your user types one sentence into the AI assistant inside your product: “cancel the three duplicate invoices and refund the customer.” Nine words, one breath, and without noticing it they have asked for three completely different kinds of thing.

Somebody has to decide what happens next, and the decision has nothing to do with how smart the model is. It's about permission: which of those actions the agent should simply do, which should wait for the user's yes, and which should never be possible at all. This post works through that for anyone choosing or building the permission model of an in-product AI agent: what the options are, why the best one asks surprisingly rarely, and how to tell whether a platform's “granular permissions” are the real thing.

One sentence, three different risks

Take the sentence apart. Before anything gets cancelled, the agent has to work out which three invoices are the duplicates, and that means reading: opening the account, scanning the invoice list, comparing amounts and dates. Reading changes nothing. If the agent stopped to ask “may I look at invoices?” the user would be right to wonder what they're paying for. Door one: just do it.

Then comes the cancelling, and now the books change. Maybe the customer already got an email with one of those invoice numbers in it. Maybe finance has a spreadsheet pointing at them. Maybe one of the three isn't a duplicate at all and the model misjudged by a hair. A person would want to see exactly which invoices before this happens, and seeing takes two seconds. Door two: ask me.

Then the refund. Money leaves the building. In plenty of products refunds belong to a finance role, done on a particular screen by a particular person, and the support rep typing this sentence doesn't hold that role at all. For this user, in this product, the third door doesn't exist. (In your product the refund might be an ask instead. That's the point. Nobody can look the answer up for you; it's a decision about your business, and someone has to make it on purpose.)

One sentence, three verbs, three risks, three different answers. Every serious permission model for an AI agent turns out to be a version of this, and the vocabulary is plain: each action gets exactly one of Allow (it runs without approval), Ask (it waits for the user's approval before it runs) or Deny (the agent cannot use it at all). The granularity is the whole trick. A model with one global switch, “autonomous” or “supervised,” makes the same decision for reading an invoice and for refunding one, and it is wrong about at least one of them. The unit has to be the action.

Fig. 1 — One sentence, three doors

The yes budget

Now picture the cautious version. A team, quite reasonably nervous, sets the agent to ask before everything. On Monday the user asks it to rename a saved filter and gets “Approve this action?” They approve. They ask for the overdue invoices: approve. They ask what's going on with the Henderson account: approve, approve, approve. By Wednesday the thumb moves before the eyes do. By Friday one of those approvals is a refund that should not have gone out, and it gets exactly the same thumb as the forty before it. That approval was human in the technical sense and a decision in no sense at all.

There is a second ending, the sensible one. The user gets tired of the prompts and quietly stops asking the agent for things. Back to the menus and the clicking. Both endings are failures, and they share a cause.

Call it the yes budget: the number of approvals a user will give an agent before they stop reading them, or stop using it. Nobody writes it down, every user has one, it's smaller than you'd hope, and it refills slowly. Every Ask you configure spends from it. Allow spends nothing. So, worth noticing, does Deny, because a no the user never sees costs nothing to issue.

That reframes the whole design problem. The question stops being “what's the safest setting?” (Ask on everything, obviously, which turns out to be the least safe, because it trains the reflex that defeats it) and becomes “where do I want the user's rationed attention to land?” Spend it on what can't be taken back: money moving, data leaving, a message going to a customer, a record disappearing. Make everything else free. A decent first pass is to sort your actions by effect, meaning read-only, repeat-safe (idempotent, so doing it twice does what doing it once does) and destructive. That is triage. Effect tells you where to look; the disposition is still a decision.

The budget moves, too, which is what makes this a gradient and not a switch. An action users approve every single time without a flicker of doubt is spending their attention for nothing, and it's a candidate for Allow. An action where the answer is sometimes no is where the Ask earns its keep. That is what earning permission looks like in practice: a record of boring yeses, read by someone who then widens the door a notch.

Fig. 2 — Two agents, one week of approvals

Whose keys

Before any of those dispositions mean anything, there's a prior question that demo-grade agents answer without noticing they've answered it. When the agent calls your API, whose keys is it holding?

The first answer is its own: a service account with whatever access the team gave it so it could do the job for anybody. That is quick to build and deserves a hard look, because of what it is. One identity powerful enough to do anything any user might ask, shared by all of them, with a sentence in a prompt as the only thing between a user and everything that identity can reach. The customer who shouldn't see another customer's invoices is protected by the model's manners. Allow, Ask and Deny still help, but only for the actions you remembered to list, and the credential underneath is bigger than every user it serves.

The second answer is the user's. The agent acts inside the signed-in person's own session and does what that person could do by clicking. Mechanically, that means the action has to run where the session lives, which is the user's browser: the model asks for an action, the policy is checked, the request goes to the open page, and the page sends it to your API with the user's own cookies or token. Your API checks permissions exactly as it would for a click, because as far as it can tell, it was one. The platform running the agent holds no credentials for your backend. (It still has to know who the user is, to keep their conversations theirs, and that is a separate token your server signs. The two identities never cross: the token never reaches your backend, and the session never reaches the platform.)

The consequence is the cleanest sentence in this whole topic: the agent can never do more than the user could. Treat the user's own permissions as a ceiling. Allow, Ask and Deny can only lower it from there. That makes Allow a statement about approval and nothing more: it says “doesn't need a yes first,” and it says nothing about whether the action is permitted. If the support rep from the opening has no refund permission, an Allow on the refund action changes nothing, because your API refuses it exactly as it would refuse the rep's own click.

There is an honest price, and you should know it before choosing. Running in the browser means an action needs an open page. If the user closes the tab with a request waiting, nothing is lost, but nothing runs either until someone opens the conversation again. That's a good property when the approval is going to arrive on Monday and a poor one if what you wanted was an agent working alone at 3 a.m. Pick the model that matches the product you actually have.

Fig. 3 — The agent's reach: its own keys versus the user's session

What the model never sees

Now the third door. There are two ways to say no to an AI model, and they sound like the same thing.

The first is to refuse. The tool sits in the model's list, the model calls it, and something replies “not permitted.” Look at what just happened: the model now knows the tool exists, knows its name and shape, and has learned it is guarded. Even if the refusal is enforced in code, you have turned a rule into a negotiation. A polite user pushes on it. A cleverly worded message pushes on it. A line of text buried in a web page the agent read pushes on it. And the model starts looking for a side door: a different tool, a different phrasing, a different sequence of steps that ends in the same place.

The second is to withhold. A denied action never appears in front of the model in the first place. The model's whole world is the list of tools it was handed, so a tool missing from that list is not a locked door but a blank stretch of wall, with nothing to call, argue with or be talked into. That's the property to look for: the model only sees the tools it has been granted, and a Deny means the action is excluded from what the agent can use. Ask has the same shape one step later. An ask-first action must never reach the browser without the user's approval, which means the check has to live on the server, before the request leaves, and not in a confirmation dialog in front-end code that somebody could skip.

Two quieter rules make withholding stronger than it sounds. Grants are by name, with no wildcard, so the endpoint your team ships on Tuesday isn't something the agent can do on Tuesday; someone has to put it on the list. (Registering an operation and letting an agent use it are separate steps. Boring. Load-bearing.) And an agent's own settings can tighten a policy but never loosen one: it can require approval for an action marked Allow, but it can't relax an Ask or a Deny set above it. Most restrictive wins, which is the only version of that rule that survives six months of people editing settings.

Asking well

Ask is the expensive door, so the job is making each one worth what it costs. Ask rarely: if a human glance wouldn't change what happens, it isn't an Ask, it's a toll booth. Ask specifically: the request should name the exact call, so “cancel invoices 4471, 4472 and 4473” instead of “the assistant wants to perform an action.” A yes to a vague question is a yes to anything, and a vague approval is mostly a ritual that lets everyone feel better.

And ask where the user already is. When the agent hands part of a job to a background sub-agent, the approvals shouldn't scatter into a second inbox. They should surface in the same conversation, labeled with who is asking, with the sub-agent waiting for the answer. Delegating shouldn't widen anything either: a sub-agent works with its parent's grants, and a Deny is as unavailable to it as to the parent.

One less obvious habit: make the wait cost nothing. If an approval has to be answered in the next few minutes or the work is thrown away, the user's real choice is between a fast yes and losing everything, and fast yeses are exactly what drains the budget. Better to let the work park where it stopped and resume when the answer arrives, even days later. An Ask nobody is rushed to answer is an Ask somebody reads.

The nahhh section

You've been waiting since the nine words. Fine. Go.

Nahhh #1: “Users will just click yes.” They will. Concede it completely: an approval is only as good as the attention behind it, and attention is the yes budget again. A button never made an action safe; a person looking did, and people stop looking when you ask too often or too vaguely. But follow the objection to its end. If your users click yes on everything, you haven't proved approvals are useless, you've proved you issued too many. Cut them until each one is a little surprising, and keep the ones where the answer is sometimes no.

Nahhh #2: “Our API already enforces permissions.” True, and that is the point. If the agent acts in the user's own session, your API is the only wall that ever mattered and it is still standing exactly where you built it. But Allow, Ask and Deny answer a different question from your API's. Your API answers “may this user do this?” The disposition answers “should this happen without the user looking?” A support lead may well be permitted to refund anything and still not want a language model doing it on a hunch. One question is authorization, the other is consent, and you need both.

Nahhh #3: “Agents should be fully autonomous. Approvals are a crutch.” Half true, and the true half is about direction. Allow is autonomy, and reads are fully autonomous from day one. Nothing in a gradient argues against more of it. The argument is that autonomy gets granted one action at a time, on the evidence of boring yeses, instead of as a mood about how capable the model feels this month.

When the policy layer is the product

Everything so far assumed a human at the keyboard, spending a yes budget. Now remove the human.

Your customers will soon be handing their to-do lists to agents of their own, and before long one of those agents will arrive at your product with credentials and an instruction that looks a lot like our nine words. Run the three doors against it. Door one survives, because a read is a read. Door three survives and matters more, because a machine never gets a bad feeling about an action. Door two is where it gets strange. An Ask assumes a person on the other end. When an agent is calling your product for another agent, who answers? Maybe the customer's human, maybe a policy the customer wrote, maybe nobody, and the request waits. That is a question without a settled answer, and we'd rather leave it visibly open than pretend.

What isn't open is where the answer has to live. For most products the interface has been the policy all along: a button that isn't on the screen is an action that doesn't exist, and nobody wrote the rule down because the layout enforced it. The moment software other than your own UI starts calling your product, the screen stops being the policy. The table you've been building in this post (which actions run unattended, which need a human, which don't exist) becomes the real description of what your product lets software do, and it is what an outside agent will negotiate against. That makes it closer to being the product than the screens ever were.

Teaflask is the layer we build around that table. Every API operation you register as an action carries Allow, Ask or Deny; the agent sees only the actions it has been granted by name; and every action runs as the user, in their browser, so your API sees an ordinary request from that user. The trust model is written down in the architecture docs, and the buyer's guide maps the wider field. Today the nine words come from a person with a thumb and a budget. Write the table before they come from something with neither.