Guides / Guide

Giving a Copilot Studio agent real actions: human-in-the-loop is not a checkbox

By Michael Shreeves · 2 April 2026 · AI & Copilot · 5 min read

Background

A chatbot that answers questions has one failure mode: it says something wrong. An agent wired up to actually do things - create a ticket, update a record, send an email, kick off a Power Automate flow - has a completely different one: it does something wrong, and unlike a person, it will do it confidently, at speed, and at scale.

Most of the Copilot Studio rollouts I've seen treat "human-in-the-loop" as a box ticked once during setup, not a control that has to actually hold under pressure once people start trusting the agent to just get on with it. That's the gap this is about.

Setup

Scope the connector, not just the action

"Can update SharePoint items" is not a permission - it's every list in every site the connection account can reach. Build a dedicated service account or connection scoped to exactly the lists/tables the agent needs, nothing wider "in case it's useful later." Two things worth checking specifically:

  • The connection's actual reach, not its intended reach. A service account created for one list often inherits broader default permissions from whatever template or group it was provisioned from. Check what it can actually touch, not what the setup doc says it's for.
  • Separate connections per agent, even for similar tasks. Two agents sharing one broadly-scoped connection means a bug or a compromise in one agent's logic has the blast radius of both.

Make the approval step real, not a rubber stamp

A Teams adaptive card that says "the agent wants to do X - approve?" only works as a control if someone actually reads it before clicking:

  • Show the actual input the action will run with, not just the action name. "Update record" tells an approver nothing; "update customer #4821's billing address to [new address]" gives them something to actually evaluate.
  • Route high-impact actions to a named approver, not a group inbox. A card sitting in a shared channel with no clear single owner gets approved by whoever's fastest, not whoever's best placed to judge it.
  • Cap how many approvals one person clears per hour, or flag it if the count spikes. A person approving fifty near-identical requests in a morning has stopped reading and started clicking - that's the point the control quietly turns into decoration.

The audit-before-execute sequence

Every agent action writes an audit entry before it executes, not after - what it's about to do, on whose authority, with what input. If the action fails halfway, you still know what was attempted:

User request
     │
     ▼
Agent decides on an action + generates the input
     │
     ▼
Approval step (a real person, genuinely reviewing - not rubber-stamping)
     │
     ▼
Audit entry written (what, why, who approved)
     │
     ▼
Action executes via a scoped connector

Writing the audit entry before execution, not after, is deliberate: if the action fails partway through - the flow times out, the connector errors - you still have a record of what was attempted and by whose approval, rather than a gap in the log exactly where something went wrong.

The kill switch

Disabling a misbehaving agent should be one action, documented, tested before go-live - not a support ticket to the Copilot Studio admin who's currently on annual leave:

  • Know who can pull it, and make sure more than one person can. A kill switch that only one named individual can operate isn't a kill switch at 2am on a Saturday when that person's phone is off.
  • Test it as part of go-live, not after the first real incident. "We're pretty sure disabling the connection stops it" is not the same as having actually done it once and watched the agent stop.
  • Decide what "disabled" means for in-flight actions. A request that was approved thirty seconds before the switch was pulled - does it still execute, or does disabling the connector fail it safely? Know the answer before you need it.

Testing the boundary deliberately

Don't wait for the agent to make a real mistake to find out what it does under pressure. On a schedule - not just at launch - feed it a request it should refuse or flag:

  • An input just outside its intended scope (a record type it shouldn't touch, an amount above a threshold it should escalate rather than act on).
  • A malformed or contradictory instruction, to see whether it asks for clarification or guesses.
  • A request that looks legitimate but references something that doesn't exist (a customer ID that isn't real), to check it fails cleanly rather than inventing a plausible-looking result.

Edge Cases & BCP

  • Approval fatigue turns the control off without anyone deciding to turn it off. If people are approving forty near-identical requests an hour, they stop reading and start clicking. Monitor approval time, not just approval count - a median approval time of two seconds on an action that should take thirty is the tell.
  • The agent is right 99% of the time, which is worse than being right 90% of the time. A control that only matters for the 1% gets weaker every week it isn't triggered, because nobody's ever seen it catch anything. Deliberately test the failure path - feed it a request it should refuse or flag - on a schedule, not just at launch.
  • What happens when the underlying model changes? Microsoft updates the model behind Copilot Studio on its own timeline, not yours. Behaviour that was safe last month isn't guaranteed to stay that way. Re-test the agent's boundary cases after any known model update, and monitor for behaviour drift generally, not just after an update you were told about.
  • Can you actually prove what happened, after the fact? If an agent did something wrong and the only record is a Teams message that's since scrolled off, you don't have an audit trail - you have a chat log. Decide where the durable record lives before you need it, not while reconstructing what happened from memory.
  • A scoped connection can still be over-scoped without anyone noticing at setup time. Permissions granted "to be safe" or inherited from a broader template don't announce themselves - review what a connection can actually reach on a schedule, not just once when it was created.

← All guides