DEV Community

Manoranjan Rajguru
Manoranjan Rajguru

Posted on

Autopilots in Microsoft Foundry: The Identity Model Behind Agents That Act as Themselves

Autopilots in Microsoft Foundry: The Identity Model Behind Agents That Act as Themselves

Every agent framework eventually runs into the same wall: what happens when there's no user to act on behalf of? A ticket queue fires an event at 2 a.m. A group chat needs a status update and there are six people in the thread, none of whom asked for it. A "digital coworker" is supposed to triage incidents across a whole team, not impersonate whoever happens to be logged in when the alert lands.

Microsoft Foundry's answer to this is a new agent category called an autopilot, and it's not a prompting pattern or a orchestration framework — it's an identity primitive. If you've been building Foundry hosted agents and assumed "autopilot" was just marketing language for "very autonomous agent," this article is going to change how you scope, provision, and reason about a meaningful slice of enterprise agent architecture.

This is Day 3 of the Foundry 100 Days / 100 Blogs series. Day 1 covered crash-resilient long-running agents (leases, checkpoints, side-effect fencing). Day 2 covered the Responses vs. Invocations hosting protocols. Today we go one layer deeper into the identity plane: what actually makes an autopilot different from every other Foundry agent, how its lifecycle works across four distinct roles, and what you need to build, provision, and govern one in production.

A note on maturity: Autopilots require Frontier preview program enrollment and Microsoft Agent 365 licensing at the time of writing. Treat the identity model as stable conceptually, but expect API and licensing details to shift before general availability. (verify current program status before building on this in production.)

Table of Contents

The Problem: Agents Without a "Self"

Standard Foundry hosted agents — the kind we've covered in this series so far — authenticate as a service principal (the agent identity) and, in most assistive scenarios, act on behalf of a signed-in user. That model is fine for a request/response assistant: a user asks, the agent does something scoped to that user's permissions, done.

It breaks in two specific, common enterprise situations:

  1. No user in the loop. An event-triggered agent — a webhook from a CI pipeline, a monitoring alert, a scheduled sweep of stale tickets — has no signed-in user to impersonate. Under the assistive model, it simply can't take Microsoft 365 actions like sending an email, updating a document, or posting to a channel, because there's no one whose permissions it can borrow.
  2. Group settings. In a Teams group chat, "on whose behalf" has no correct answer. Attribute the action to whoever sent the last message and now a compliance officer's permissions apply to a thread they weren't paying attention to, or worse, other members get exposed to content scoped to that one person's access.

Both problems have the same root cause: the agent has no identity of its own in Microsoft 365. It's infrastructure, not a participant. An agent user account — a genuine Entra user object with a mailbox, a Teams presence, a manager, and a place in the org chart — resolves this by giving the agent something to be rather than something to borrow.

That's the entire idea behind an autopilot. Everything else in this article is really an elaboration of that one design decision.

What Actually Defines an Autopilot

It's tempting to define autopilots by their capabilities — memory, planning, proactivity, learning. Resist that framing; Microsoft's own docs explicitly call it out as the wrong model, and I think they're right. Capabilities are a feature list. They change every release. If a capability set defined the category, an assistive agent that gains long-term memory in the next SDK bump would silently become an autopilot without anyone deciding that it should hold a standing role or answer to a manager. That's an accident, not an architecture.

Autonomy doesn't define it either. A background-service agent (see the table below) can run unattended all day, restarting VMs or reconciling data pipelines, and it's still not an autopilot — it has no presence in Microsoft 365 at all. Autonomy and identity are orthogonal.

Identity is the only reliable definition. An autopilot is any Foundry agent that has, in addition to the agent identity every agent gets, an Entra agent user account. That's a binary test: either the account exists or it doesn't. Nothing else needs to be true.

The Identity Model: Agent Identity vs. Agent User Account

Every Foundry agent, from the moment it's created, gets an agent identity — a service principal produced by an agent identity blueprint. It has an ID, a name, a sponsor, and the permission set the agent authenticates with at runtime. For a regular agent, that's the whole identity story: one blueprint, one agent, one identity, full stop.

An autopilot adds a second object on top: the agent user account. This is a genuine Entra user object — not a service principal wearing a costume — with a display name, a user principal name, a manager, a mailbox, a Teams presence, and a slot in the org chart. It's what lets the autopilot send an email as itself, get @mentioned in a channel, and be treated as a teammate rather than a webhook target.

Object Type Holds Used for
Agent identity Service principal Agent ID, name, sponsor, runtime permissions Authenticating infrastructure calls; securing the running container/process
Agent user account Entra user object Display name, manager, UPN, mailbox, Teams presence Acting as itself in Microsoft 365 — sending mail, posting in Teams, editing docs

These two objects are never interchangeable and they do different jobs at different layers. For an autopilot, the agent identity secures the infrastructure that runs the agent (think: the container's managed identity calling Azure resources), while the agent user account represents the autopilot the moment it reaches into Microsoft 365.

Diagram comparing the one-to-one identity model of a regular Foundry agent against the one-to-many identity model of an autopilot blueprint

This distinction matters architecturally because it changes the shape of the object graph. A regular agent is one-to-one: one blueprint produces exactly one agent, with exactly one agent identity, and no user account. An autopilot is one-to-many: one blueprint is hired repeatedly, and every hire produces a new instance with its own agent identity and its own agent user account. Ten teams hiring the same blueprint means ten agent identities, ten mailboxes, ten distinct sets of group memberships — sharing one codebase and one declared capability set, but not sharing a single runtime identity or a single grant of access.

Three Agent Types Foundry Supports

Foundry doesn't force every agent into the autopilot model — most agents shouldn't be autopilots. There are three categories, distinguished entirely by identity:

Type Identity Behavior Best fit
Assistive Agent identity + signed-in user context Acts on behalf of a user, constrained to that user's permissions Personal productivity — a meeting-prep agent that drafts a deck when asked
Background service Agent identity only Acts as itself via app-only permissions; autonomous but no Microsoft 365 presence Backend automation — an ops agent that restarts a VM in response to an alert
Autopilot Agent identity + agent user account Acts as itself in Microsoft 365, including group settings; autonomous within a defined scope Digital coworkers — a release manager that coordinates work across a Teams channel

If your agent's job is "do this thing when I ask," it's assistive. If it's "run backend jobs no human watches," it's a background service — and functionally this is closest to what we discussed for long-running hosted agents in Day 1 of this series. Only reach for an autopilot when the agent genuinely needs a standing, addressable identity that a whole team interacts with — because that identity comes with real overhead: licensing, a manager, onboarding, and ongoing governance.

Why You Build a Blueprint, Not an Autopilot

Here's the part that trips up developers coming from a "just deploy the agent" mental model: you don't create an autopilot directly. You build and publish a blueprint — a declared role, a set of tools, a permission scope, and behavioral logic — and then teams hire instances from that blueprint. Each hire is a separate autopilot with its own identity and its own team-scoped grants.

The reason is structural, not bureaucratic. Suppose you build the agent directly and grant it access to your team's SharePoint site and security group. That access is exactly what makes it useful to your team — and exactly why no other team can reuse it. They'd inherit your team's access, which they shouldn't have, so they build their own near-identical agent. Multiply by ten teams and you get ten independently-governed copies of the same logic, whose behavior drifts apart over time and whose compromised-tool blast radius has to be chased down one agent at a time.

A blueprint separates what the agent can do (declared once, by a developer, and approved once, by a tenant administrator) from what a specific instance can reach (granted per-team, by a manager, at hire time). One codebase, many independently-scoped identities. This is the same logic that governs container image reuse across microservice deployments, applied to agent identity instead of compute.

The Autopilot Lifecycle: Four Roles, Three Layers

Because the blueprint/instance split is real, the lifecycle isn't a single line from "create" to "delete" — it runs at three layers simultaneously, each owned by a different role:

Stage Layer Owner Produces Reversible?
Provision infrastructure Blueprint Azure administrator Dev environment + platform resources Yes
Build and publish Blueprint Developer A published blueprint with declared scopes and ceilings Yes
Approve, configure, consent Blueprint Tenant administrator An activated, hireable blueprint Yes
Hire Instance Manager Agent identity + agent user account Yes (via offboarding)
Onboard Instance Manager / access manager Audience, scopes, and resource access Yes
Operate Instance Manager, teammates, business leads Day-to-day work, observation, coaching Yes
Offboard Instance Manager Removed instance No
Retire / delete Blueprint Tenant admin / developer Blocked-from-new-hires or fully deleted blueprint Retire: yes. Delete: no

Layer 1 — Blueprint (runs once)

The Azure administrator provisions the Foundry account, project, container registry, and observability stack, and grants the built-in identity access to whatever storage the agent needs (state tables, checkpoints, memory). This is per-environment work, not per-agent — every blueprint built in that environment inherits it.

The developer then defines the blueprint: its role, its tools, when it replies versus stays silent, when it escalates for human approval, and — critically — two ceilings that every downstream role trusts: who is allowed to hire this blueprint and the widest access any single manager can ever grant an instance. Nothing is actually granted at this stage. Publishing is a declaration, not a permission grant; an autopilot can be published with every scope it will ever need and still touch zero real data until someone hires it.

The tenant administrator is the fleet-level gate. They review the declared scopes, grant admin consent (which can be partial — a tenant admin can approve a blueprint while consenting to only a subset of what it asked for), and decide who's eligible to hire it. This is the point where "can this operate in our tenant at all, and under what policy" gets decided, and it's re-triggered any time the blueprint's scope widens.

Layer 2 — Instance (runs once per hire)

Hiring creates the two identity objects in a single action, and the person who hires becomes the manager. Multiple teams can hire from the same blueprint independently and simultaneously — one design, many fleets.

Onboarding is where the manager (or a delegated access manager, when the manager doesn't hold rights to add accounts to security groups or DevOps orgs) configures five things: audience, listening scope, messaging scope, resource access, and source of truth. This is the first point in the entire lifecycle where real business data access is granted. It's worth internalizing the two-gate model here:

  • Consent (set at the blueprint layer, enforced by Entra ID) governs what kinds of calls are allowed at all — the token's scope.
  • Access (set at onboarding, enforced by each resource — SharePoint, DevOps, a security group) governs what data those allowed calls can actually reach.

A blueprint can be fully consented and still reach nothing, because access is a separate grant made per-instance, at hire time, by a human who has to actually add the account to a group.

Operating is four concurrent activities for the life of the instance: teammates use it across Teams/email/document surfaces; the manager and business leads observe it (what did it do, for whom, at what cost); anyone close enough to see a problem can govern it by tightening access or blocking it outright (asymmetric by design — blocking is easy, unblocking requires a tenant admin); and the manager alone coaches and customizes it (style, memory edits, routine shaping), while objective corrections (a wrong date, a wrong owner) can come from any teammate and simply update grounding data.

Offboarding is the one irreversible instance-level action — the instance is gone, not paused.

Layer 3 — Fleet (a standing activity, not a stage)

Once a blueprint is approved, the tenant administrator's job becomes continuous: observing every instance across every team that hired it, and blocking the blueprint entirely if something is systemically wrong. Deleting the blueprint cascades and removes every instance hired from it — which is the sharpest edge in the whole model, and worth flagging loudly to whoever owns blueprint lifecycle in your org.

Diagram showing the autopilot lifecycle across the blueprint, instance, and fleet layers with roles at each stage

Implementation Walkthrough: Provisioning Your First Autopilot

The foundry-samples repository ships working autopilot samples in both C# and Python (samples/python/foundry-autopilot-agent). The mechanics map directly onto the lifecycle above. Here's the developer-facing path using Azure Developer CLI:

# Sign in to both CLIs against the target tenant
az login --tenant <tenant-id>
azd auth login --tenant-id <tenant-id>

# One command runs three lifecycle stages back-to-back:
#   1. provisions infrastructure (Azure administrator's stage)
#   2. builds the agent blueprint (developer's stage)
#   3. publishes it for tenant admin approval
azd provision
Enter fullscreen mode Exit fullscreen mode

That single azd provision call is doing more than it looks like. Under the hood it:

  1. Creates a Foundry account/project, an Azure Container Registry, Log Analytics, and Application Insights.
  2. Assigns the project's managed identity AcrPull and Log Analytics Reader — the RBAC work that plain Contributor access can't do for you, which is why the docs are explicit that you need Owner, or Contributor + Role Based Access Control Administrator, at resource group scope.
  3. Compiles your agent code into a container image, pushes it to the registry, and registers a hosted agent + first version. This step mints the agent identity blueprint and the agent's own agent identity — you don't create these Entra objects yourself.
  4. Submits the result as an autopilot blueprint request to the Microsoft 365 admin center, where a Global Administrator or AI Administrator approves it.

If you'd rather run each stage under different credentials (common in real orgs, since the Azure admin, developer, and tenant admin are rarely the same person), skip the composite command and call the sample's scripts/ entries directly, or preview first:

azd provision --preview   # see what gets created without committing
Enter fullscreen mode Exit fullscreen mode

Once approved, hiring happens outside the CLI entirely — in Microsoft Teams, under Apps → Agents for your team — which is a deliberate design choice: hiring is a manager's HR-like action, not a deployment action, and it shouldn't require touching infrastructure tooling.

Enabling a delegated tool: Azure DevOps MCP

Autopilots frequently need delegated access to enterprise tools. The sample wires up the Azure DevOps MCP server as an opt-in tool:

azd env set AZURE_DEVOPS_ORGANIZATION <organization-name>
azd provision
Enter fullscreen mode Exit fullscreen mode

At runtime the agent requests a delegated token for https://mcp.dev.azure.com/.default. Two conditions must both hold for this to work: the agent blueprint's Entra application needs the Ado.Mcp.Tools delegated permission against the DevOps resource application, and whichever identity the call runs under (the agent user account, for an autopilot) needs actual DevOps org membership. This is the consent-vs-access split from the lifecycle section, made concrete: consent is a one-time Entra grant on the blueprint; DevOps org membership is a per-instance access grant a manager has to make.

Debugging a failed session

If a run fails, the response includes a session ID you can use to stream hosted-agent logs directly — useful because autopilot failures often surface as Teams-side silence rather than an obvious stack trace:

eval "$(azd env get-values)"
export FOUNDRY_AGENT_SESSION_ID="<session-id-from-error-response>"
ACCESS_TOKEN="$(az account get-access-token --resource https://ai.azure.com --query accessToken -o tsv)"

curl -N \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Accept: text/event-stream" \
  -H "Cache-Control: no-cache" \
  -H "Foundry-Features: HostedAgents=V1Preview" \
  "https://$ACCOUNT_NAME.services.ai.azure.com/api/projects/$PROJECT_NAME/agents/$AGENT_NAME/sessions/$FOUNDRY_AGENT_SESSION_ID:logstream?api-version=2025-11-15-preview"
Enter fullscreen mode Exit fullscreen mode

Runtime Behavior: What Happens When a Message Arrives

Once hired and onboarded, an autopilot instance is a running hosted agent behind the scenes — same execution model we discussed in Day 2's Responses vs. Invocations article — but every inbound event now has to clear an identity gate before it reaches the model:

  1. A message lands on a configured surface (Teams DM, group chat, channel mention, email, document comment).
  2. The runtime checks the sender against the instance's audience. Anyone outside the configured audience is a non-teammate and is blocked before the agent ever calls a model — this is a hard boundary, not a prompt-level instruction to "ignore unauthorized users."
  3. For in-audience senders, the listening scope determines whether this surface/conversation is even being received, and the messaging scope determines who the autopilot is allowed to message back.
  4. If the turn requires reaching a business resource (a SharePoint site, a DevOps project), the call authenticates as the agent user account and is checked against that resource's own membership lists — Entra's consent gate and the resource's access gate are evaluated independently, and neither substitutes for the other.
  5. Application Insights captures the turn as a GenAI span. The foundry-autopilot-agent sample tags the enclosing span invoke_agent FoundryDigitalWorker, with gen_ai.agent.id and microsoft.gen_ai.main_agent.id both formatted as <agentName>:<agentVersion>, plus a gen_ai.response.id that ties back to the underlying Responses API call — the same attribute you'd use for trace-based evaluation pipelines.

This is worth sitting with: the model never even gets invoked for a blocked sender. Compare that to an assistive agent guarded only by system-prompt instructions ("don't respond to users outside group X") — that's a much softer boundary that depends on the model correctly refusing, versus Entra rejecting the call outright.

Production Considerations

  • Consent re-review is a rollout tax. Every new blueprint, and every widened scope on an existing one, re-enters the tenant admin approval gate. If your team ships weekly, budget real calendar time for admin review — this is not a CI/CD-speed loop.
  • Blueprint deletion is destructive by cascade. Deleting a blueprint removes every hired instance across every team, with no undo. Treat blueprint deletion with the same caution as deleting a shared IAM role that dozens of services assume.
  • Instances drift independently. Because coaching and access grants happen per-instance, two autopilots hired from the same blueprint six months apart can behave meaningfully differently. Track blueprint version alongside instance-level customization if you need to reason about behavior parity across teams.
  • License seats are a hard runtime dependency. Each instance consumes an Agent 365 license seat at hire time, not at build time. A blueprint can pass every build and publish step and still fail at the hire step if the tenant is out of seats — check seat count before onboarding a new team, not after a failed demo.

Security Considerations

  • Two independent gates, not one. Never assume that granting a scope in the blueprint's consent step is equivalent to granting data access. Consent controls what kinds of calls are legal; group/site/org membership controls what those calls can reach. A security review of an autopilot has to check both, separately.
  • Non-teammates are blocked at the identity layer, not the prompt layer. This is a meaningfully stronger boundary than instructing a model to refuse out-of-scope senders, and it's worth calling out explicitly in any threat model — the model literally isn't invoked for blocked senders.
  • Accountability is asymmetric on purpose. Anyone who can see the autopilot misbehaving — manager or business lead — can block it. Only a tenant administrator can unblock. Fault and obligation are deliberately decoupled: an access manager's misconfiguration might cause the incident, but the manager is still the one obligated to stop the instance. Bake this into your incident runbooks so the right person knows they're on the hook regardless of root cause.
  • The developer's declared operating envelope is the liability boundary. If an autopilot fails outside the conditions it was built and tested for, fault hinges on whether that envelope was documented at publish time. Don't publish a blueprint with vague or absent behavioral bounds — "what it must never do" is a required design artifact, not an afterthought.

Cost and Licensing Considerations

Autopilots carry licensing overhead that regular hosted agents don't:

  • Tenant enrollment in the Frontier preview program, plus acceptance of Microsoft Agent 365 terms of service.
  • At least one Microsoft 365 Copilot license or Agent 365 license in the tenant (Microsoft E7 qualifies).
  • A Frontier preview seat per instance — eligible tenants get a 25-seat preview allocation after enrollment, and each hire consumes one seat because each hire mints a genuine agent user account. (verify current seat allocations and GA pricing before committing a rollout plan, since this is explicitly preview-tier licensing.)

Compute cost is otherwise the same shape as any Foundry hosted agent: container build/registry costs, model inference, and Application Insights ingestion. The licensing cost is the differentiator, and it scales with instances hired, not with blueprint complexity — ten teams hiring a simple blueprint costs more in seats than one team hiring a sophisticated one.

Common Mistakes and Pitfalls

  1. Treating "autopilot" as a synonym for "very capable agent." Teams add memory and planning to an assistive agent and start calling it an autopilot in internal docs. This causes real confusion later when someone assumes it has a mailbox and it doesn't.
  2. Building the agent for one team and being surprised no one else can reuse it. This is the exact failure mode the blueprint/instance split exists to prevent — if you skip it, you'll end up governing N near-identical agents independently.
  3. Assuming consent implies access. A newly hired instance can pass every scope check and still 403 against a SharePoint site simply because nobody added its agent user account to the right security group yet. Onboarding is not optional plumbing — it's the actual data-access grant.
  4. Under-provisioning license seats before a team rollout. The build and publish steps succeed with zero seats available; only the hire step fails. Check seat count first, not after a live demo to stakeholders.
  5. Not stating the operating envelope at publish time. Skipping "what conditions was this built and tested for" leaves fault ambiguous the first time the autopilot does something unexpected outside those conditions — exactly when you need that documentation most.
  6. Deleting a blueprint without accounting for cascade. Because delete is irreversible and removes every hired instance tenant-wide, treat it like deleting a production database, not like deleting a feature branch.

When Not to Use an Autopilot

Skip the autopilot model when:

  • The agent only ever acts in response to a specific, signed-in user's request — an assistive agent with delegated permissions is simpler, cheaper, and needs no Agent 365 licensing.
  • The workload is purely backend automation with no Microsoft 365 surface at all (restarting infrastructure, reconciling a queue) — a background-service agent gets you autonomy without the identity and licensing overhead.
  • You're prototyping. The consent/approval gate involves a tenant administrator by design; that's friction you don't want in an early experimentation loop. Build assistive first, graduate to autopilot once the "who does this act as" problem is real and recurring.

Practical Recommendations

  • Start every autopilot design by writing down the operating envelope — what it does, what it must never do, and the conditions it was tested under — before you write the blueprint's tool manifest. This becomes both your test plan and your liability boundary.
  • Model consent scopes and access grants as two separate reviews in your own change process, mirroring the platform's two-gate design. Don't let a single "approved" checkbox stand in for both.
  • Instrument for the gen_ai.agent.id / gen_ai.response.id attributes from day one if you plan to run trace-based evaluations later — retrofitting observability onto a fleet of live instances is much harder than baking it into the blueprint.
  • Nominate an access manager explicitly for any team whose lead doesn't hold DevOps/SharePoint admin rights, rather than letting onboarding stall on a permissions gap.
  • Track blueprint version against instance customization state so you can answer "why does Team A's autopilot behave differently from Team B's" without spelunking through coaching history.

Conclusion

The autopilot model is Microsoft Foundry making an explicit, structural bet: that the hard problem in enterprise agent deployment isn't capability, it's identity — who is this thing, on whose authority does it act, and who answers for it when it doesn't. The agent identity / agent user account split, the blueprint/instance/fleet layering, and the four-role accountability model aren't incidental plumbing; they're the actual architecture. If you're building anything that needs to act as itself in a group setting — coordinating a Teams channel, triaging a shared inbox, standing in for a role rather than a request — understand this model before you reach for memory or planning features, because identity is the layer everything else depends on.

Next in the series, we'll look at how Foundry's cloud evaluation SDK pipelines let you continuously score both agents and autopilot instances in production, and where trace-based evaluation on gen_ai.response.id fits into that loop.

References

Top comments (1)

Collapse
 
jo-do profile image
Jo Do

The "no user to act on behalf of" wall is real and most frameworks pretend it away. Giving the agent its own identity primitive instead of borrowing whoever happens to be in the thread fixes a whole category of audit and permission questions at once - whose token, whose consent, whose blame. The 2 a.m. ticket queue example is the right anchor: acting "as the on-call human" is how you get actions nobody approved wearing somebody's name.