Agent Approvals: The Writes That Should Wait for a Click

We already have a test for "agent-native": can the assistant actually file the request, under your permissions, in the same audit trail. That post is the parity rule. This one is the exception that makes the rule safe.
Parity is not "the agent can do everything instantly." Some writes should not run from a token at all, even yours. Erasing someone, publishing a leave policy, changing retention, starting a process that will email the company: those are the kind of action you want to look at on a screen you opened on purpose, not the kind you want confirmed in a chat window you were using to ask about Friday.
Chat confirm is the wrong shape
Assistants already have an "ask before you act" setting. It is a good setting for "log 6 hours on Platform v2." It is a bad setting for "delete this person's personal data."
A chat confirm is a sentence in a thread. It is easy to approve the wrong sentence. It is easy to approve it twice. It is easy to miss that the name in the argument is not the name you are looking at. And the confirm lives in a product that is allowed, by design, to be a little eager. The whole point of an agent is that it takes the next step.
The shape that actually holds up is slower, and a bit annoying, which is the point.
- The assistant calls the tool. Nothing in the workspace changes. The response is a proposal: a review URL, and a clock 30 minutes out.
- You open that URL while signed in as the same person who connected the agent. Another signed-in user cannot decide it. A bearer token cannot decide it either, even if a cookie is also present. The decision is a browser session, on purpose.
- The dialog shows the target, and for a policy or a workspace setting, a current-versus-proposed table. Approve does not run the change. Reject leaves the workspace untouched.
- You go back to the assistant. It checks the status. Only
approvedlets it call the same tool a second time, with identical arguments plus the approval id. Different person, different field, expired proposal, interrupted commit: all refuse.
The review cannot edit values. If the table is wrong, you ask for a new proposal. That is also the point. A dialog you can nibble into a different erasure is a dialog that will erase the wrong person.
A short list, not a vibe
The list is short so it can stay honest.
erase_employee. GDPR erasure of someone already offboarded. Irreversible. The first call only prepares. We have been specific about what erasure removes and what it keeps; doing it from a chat token would make the irreversible part a conversation.
update_leave_policy. Publishes a new policy version for everyone enrolled. Carryover caps, notice, booking increments, the requirement to name a cover. A quiet publish on a Friday afternoon is how 80 people discover on Monday that their unused days expire.
update_workspace_settings. Includes retention that can delete records, and the public calendar feed. Retention is a destroyer. The calendar feed is a bearer URL. Neither belongs in a tool that runs because the assistant was being helpful.
start_process. Starts a process for one person or a team: onboarding, offboarding, a policy rollout. It can notify people and call integrations. A misfired offboarding is not "oops, undo."
update_leave_type, update_allowance, apply_leave_preset. Changes to the leave setup people already have. A changed leave type or allowance, or a country preset applied to the workspace, changes what people are entitled to, the same way a policy publish does. Creating a new leave type or allowance, putting someone in a policy and a one-person balance correction run at once, on the ledger.
update_employee, invite_employee, create_employee, for some calls. Fixing a job title or adding a new hire runs at once. A change of role or status, previous-employment figures that can lower statutory leave, or an invitation or hire that grants an admin-tier role waits for the review. Who holds admin rights is not a decision for a chat thread.
Booking leave, clocking in, logging time, approving a request: those do not use this review. They follow the assistant's own Ask setting and the same domain rules as the web app. If we put Friday off behind a 30-minute browser round-trip, nobody would connect an agent. The split is the product.
ChatGPT's curated catalog leaves out erasure, workspace settings, leave type, allowance and policy authoring, and starting or authoring processes. The full catalog at https://app.squadbear.com/mcp does, for Claude, Cursor, Codex, Gemini. A ChatGPT connection that cannot erase someone is not a missing feature. It is the same opinion, enforced by the allowlist.
Worked example
Marta asks Claude to require that carried Standard vacation days start by the end of September. Claude calls update_leave_policy and sends her a SquadBear URL with ?approval=…. Nothing has published.
She opens Connect an agent while signed in as Marta. The dialog lists Carryover deadline from "No deadline" to "Leave must start by the deadline," and Deadline month from "No month set" to "End of September." She clicks Approve proposal. The policy is still the old one.
She goes back to Claude. The second call publishes policy version 2. The leave ledger does not rewrite itself. Existing balances stay. The new rule applies going forward, which is what "publish a version" means, and which is why this write is on the list: it looks like a settings tweak and behaves like a company-wide event.
If she had asked Claude to erase a contractor in the same afternoon, she would have had a second, separate URL. Approving the policy proposal would not have approved the erasure. There is no "approve all my pending agent work" button. That button is how the wrong name gets through.
Thirty minutes is short on purpose. A proposal sitting overnight is a proposal someone else might feel helpful about. An interrupted commit is not retried automatically. The assistant has to come back. So do you.
What this is not
It is not a second permission model. The agent still acts as you. If you could not erase someone in the app, your agent cannot propose it either. The browser step is an extra brake on writes you can do, not a way for the agent to do writes you cannot.
It is not an excuse to skip the audit log. The publish, when it happens, is the same event the web app would have written. The proposal is not a shadow history. Workspace settings → Audit log is still the record.
It is not a general "human in the loop" platform. Ten operations, each named. If another write turns out to be as destructive as erasure, it should join the list by name, not because a framework got excited.
Where SquadBear keeps this
The in-app list is Connect an agent at https://app.squadbear.com/agents. The review dialog is the same page with ?approval=…. The docs page is Review assistant changes.
The everyday connection still covers leave, time, attendance and assigned work. The writes above wait. Ask this first, the same as in the parity post, then this one:
"Prepare a change to Standard vacation so carried days must start by the end of September, then give me the SquadBear review link. Do not commit until I approve it there."
A good assistant returns a URL and waits. A bad one publishes, then tells you it waited.
Start free and connect Claude on the full /mcp catalog, or ask the demo to show you a proposal that has not changed anything yet.
Related reading: what agent-native HR means, which is the parity rule this brake sits on, and routing HR through an AI assistant, which is what broke when we tried to live in the chat window.




