New in Impact Runs on FabrCore Read-only by design

Meet Guardian: An AI Agent Assigned to Every User We Support

Not one assistant for the whole company. One agent per person — watching their attack surface, and standing by to help our technicians the moment a ticket opens.

August 19, 2026  |  9 min read

1:1one agent per user
24/7daily unprompted check
5parallel specialists
0write permissions

Most AI in IT support looks the same: a chat box bolted to the side of a ticketing system that can summarize what a technician already typed. It is a nice demo. It does not know anything about your laptop, your sign-ins, or the inbox rule that appeared on your mailbox last Tuesday.

So we built something different inside Impact, the platform we run our managed services business on. It is called the Guardian agent, and there is one of them for every single user we support.

Guardian does two jobs. It watches one person's attack surface continuously, on its own schedule, without anyone asking. And when that person opens a ticket, it is already investigating before a technician has finished reading the subject line.

Why one agent per user, and not one per company?

Because security questions are almost always about a person. “Who signed in from overseas at 3am?” “Why did her mail stop arriving?” “Which machine threw that Defender alert?” An agent scoped to one human can hold a baseline of what normal looks like for that human — and notice when it stops being normal.

What Guardian Actually Watches

Guardian's view spans both halves of a modern user's world: the Windows machines they physically sit at, and the Microsoft 365 identity they carry everywhere else.

Identity & sign-ins

Sign-in history, risky sign-ins flagged by Microsoft, registered MFA methods, and whether an authentication method was quietly added recently.

Mailbox behavior

Inbox rules, forwarding, automatic replies, and whether mail is arriving at all. A rule the user did not create is a security event, not a preference.

Their endpoints

Which machines are actually theirs, who else uses them, live Windows event log queries, and the health of the monitoring agent on each one.

Alerts & licensing

Security alerts naming the user or their devices, plus licence assignment failures and OneDrive quota — the boring causes behind “it worked yesterday.”

Under the hood, Guardian delegates to specialists that run in parallel: an identity and security analyst, an endpoint log analyst, a mailbox analyst, a workspace analyst, and a summarizer that draws the conclusion. Each one gets only the tools its job requires. The mailbox analyst physically cannot read sign-in history. That is not a policy written into a prompt — it is the tool list it was handed at construction, and asking for a tool it does not have fails the agent at startup rather than silently at runtime.

Job One: The Ticket Arrives, and Guardian Is Already Working

Ticket-triggered investigation
seconds, not hours
1. Ticket opensA ticket is raised for a user. The platform wakes that user's Guardian and hands it the title and description.
2. Scope firstIs this one person, or the whole company? A dead internet circuit is not a laptop problem. Guardian decides before it spends anything.
3. Fan outSpecialists query identity, mail, licences, storage and event logs at the same time, each scoped to that one user.
4. ConcludeThe most likely cause, with the device named, the event id quoted, the timestamp given — and a separate list of what could not be checked.

By the time a technician opens the ticket, the boring part of the investigation is done. Not the judgment — the legwork. Which machine is hers. Whether it is even online. What the System log said at the time she reported the crash. Whether her licence quietly failed to apply overnight because the tenant ran out of seats.

That last one is worth sitting with. A licence can be assigned and still not be in force. To the user, an application simply stopped working. To a technician who has not checked assignment errors specifically, it looks like a mystery. Guardian checks it every time, because it never gets bored.

Job Two: The Daily Check Nobody Asked For

Once a day, on its own reminder, each Guardian runs a health check on the person it watches. Account still enabled. No risky sign-ins in the last 24 hours. No new security alerts. No forwarding rule that was not there yesterday. No licence assignment errors. Devices checking in, agents healthy, OneDrive not full.

Then it compares all of that against a stored baseline — and here is the part we care most about:

If nothing changed, it says nothing at all.

A guardian that reports “all is well” every morning is muted inside a week — and then the morning it has something real to say is muted too. Silence is the feature.

Most monitoring products get this backwards. They measure their own value in notifications delivered. We measure ours in notifications withheld. Guardian only speaks when the answer to “what changed?” is something a human should act on.

Both jobs — the ticket investigation and the daily check — run through exactly the same reasoning path. The daily check is just a prompt the agent sends itself on a schedule. There is no second code path quietly rotting in the corner, which is how the unattended half of most monitoring systems dies.

The Hardest Thing We Got Right: “I Could Not Check”

There is a distinction that sounds pedantic until it burns you, and it is the single idea this entire agent was designed around:

“I checked and found nothing” and “I could not check” are completely different statements. An all-clear you cannot support is worse than admitting the gap.

Here is the real scenario. Microsoft's sign-in and audit logs require an Entra ID P1 licence. Plenty of small tenants do not have one. Ask an ordinary AI assistant to check a user for suspicious sign-ins in such a tenant and it will get back one error, six other tool results that succeeded, and then write you a confident paragraph that reads: “No unusual sign-in activity was detected.”

That sentence is false, and a technician will act on it.

So every tool Guardian can call returns an explicit UNAVAILABLE marker when a check could not be performed — distinct from returning an empty result — and every instruction in the system reinforces that the two must never be flattened together. Guardian's conclusions always carry a second list: what could not be checked, and why.

What a generic assistant says

“No forwarding is configured on this mailbox.”

What Guardian says

“No forwarding rules exist. Mailbox-level forwarding cannot be read through Microsoft Graph at all and was not checked — that needs Exchange PowerShell.”

Same principle for hardware. If a machine does not answer within 90 seconds, Guardian does not report a failed query. It reports that the machine is almost certainly offline and gives you the last time it was seen. An offline endpoint is a finding, not an error.

Guardian Runs on FabrCore — Our Own Agent Runtime

Guardian is built on FabrCore, the open-source .NET agent framework our team develops. FabrCore agents are not request handlers that spin up and vanish. They are long-lived, individually addressable actors with durable state, built on Microsoft Orleans.

That distinction is what makes a per-user guardian possible at all:

It remembers

Each Guardian keeps a durable baseline of what normal looked like yesterday. That state survives restarts, deployments and idle periods.

It wakes itself

Durable reminders fire the daily check without a cron job, a queue worker, or a separate scheduling service to keep alive.

It scales sideways

Thousands of Guardians are thousands of cheap actors, activated on demand and deactivated when idle — not thousands of running processes.

It staggers itself

A 60-person customer would otherwise fire 60 agents and hundreds of Graph calls in the same second. Each Guardian jitters its own schedule so Microsoft never throttles the lot.

Why running the runtime ourselves matters

We could have rented an agent platform. We deliberately did not, and the reasons are the same ones our clients care about.

Your data never leaves our stack

Sign-in addresses, mail subjects, file names and event log text are among the most sensitive things an MSP touches. They stay inside infrastructure we operate, and sensitive telemetry capture is switched off on these agents by design — none of it belongs in a trace.

Tenancy is enforced in code, not in a prompt

Each Guardian is pinned to one customer, one user and one tenant at provisioning time by trusted code. No tool anywhere accepts a customer id, tenant id or email address as a parameter. The model can ask for anything it likes; there is nothing else it can reach.

We see every token and every tool call

FabrCore records message traffic, tool invocations and model usage per agent. We know what each Guardian costs and what it did — and every endpoint command is stamped with the specific agent that issued it.

We change it on Tuesday

A gap in the reasoning gets fixed the same week we find it. No vendor roadmap, no feature request queue, no waiting on someone else's release to unblock a client's problem.

There is one more thing worth naming, because defence in depth is not a slogan here. The pin bounds what the agent may ask for. The platform's access guard checks the agent's own role on every call. The monitoring server refuses a device query that is not scoped to a customer. And a Microsoft Graph token minted for one tenant physically cannot read another. Four independent layers, any one of which would stop a mistake on its own.

In-Process Plugins vs. MCP Servers

Guardian's tools are in-process FabrCore plugins — ordinary .NET classes whose methods become tools the model can call, running inside the same process as the agent. The popular alternative right now is the Model Context Protocol (MCP), where tools live in a separate server the agent talks to over standard input/output or HTTP.

FabrCore supports both. It has been an MCP client since early this year, and we use MCP servers where they earn their place. But for Guardian, in-process plugins were the only defensible choice. Here is the honest comparison.

  In-process plugin MCP server
Call path A direct method call inside the agent's own process. A remote-procedure round trip to another process, local or hosted.
Identity & authorization Shares the host's dependency injection container. The plugin acts as the platform's own service account and passes the same role checks every other part of the application does. Carries its own credentials and its own authorization model. Whatever the server is allowed to do, the agent is allowed to do.
Tenancy scoping The customer, user and tenant are injected at construction from trusted configuration. The model never sees them and cannot supply them. Tools are generic by design and typically take the scope as a parameter — which means the model supplies it, and the model can be wrong or be manipulated.
Failure mode A missing or renamed tool is a typed error that fails agent startup immediately, in front of a developer. A server that fails to connect is logged as a warning; the agent carries on with a quietly shorter tool list.
Latency & overhead Effectively free. No serialization, no transport, no second process to schedule. Serialization and transport on every call, multiplied across a parallel fan-out of specialists.
Deployment Ships and versions with the application. One deployable, one lifecycle. A separate process to install, supervise, restart and version independently.
Where it wins Tools that touch your own data, your own permissions model, and your customers' tenants. Third-party ecosystems, tools written in other languages, and code you did not write and want kept at arm's length.

The row that decided it for us is tenancy scoping. An MCP server is a general-purpose tool provider by design — that generality is the entire point of the standard. A hypothetical get_user_signins MCP tool takes a tenant and a user address as arguments, because it has to work for anybody. That means the scope arrives as a string the model chose.

In an MSP, that is unacceptable. Two customers legitimately have identically named accounts; in a book of business, that is a certainty rather than a curiosity. Getting the boundary wrong does not produce an error — it produces a confident, detailed, internally consistent answer about the wrong company's employee, and nothing in the output would tell you.

The rule we hold ourselves to

The model decides what to look for. Trusted code decides whose data it may look at. Those two decisions never touch. In-process plugins let us enforce that in the type system; a protocol boundary that accepts scope strings from a model does not.

There is a second, quieter benefit. Because the plugins run inside our application, they can return something better than raw data: they return judgment. A device that does not answer comes back as “probably offline, last seen at this time — this is a fact about the device, not a failure of the query.” A serial number that matches two machines comes back as both matches plus a warning that the serial is probably not unique on that hardware, rather than an arbitrary pick. A generic tool server returns a result or an error code. A plugin that lives inside the domain can hand the model the same context an experienced technician would have.

None of which is an argument against MCP. It is a genuinely good standard that solved a real problem — before it existed, every external integration meant writing yet another bespoke connector with its own authentication and error handling. When we want a third-party service or somebody else's product inside an agent, MCP is exactly the right tool and FabrCore connects to it in a few lines of configuration. It is the right answer for tools you did not write. It is the wrong answer for the boundary that separates one client's data from another's.

What This Means If We Support Your Business

Guardian is read-only. It cannot change an account, a device, a licence, a mailbox or a ticket. When something needs changing it says precisely what and who should do it, and a human does it. We think that is the correct place for the line right now, and we would rather explain a conservative boundary than a surprise.

Faster tickets

The evidence gathering is finished before a technician starts. They spend their time on judgment, not on log spelunking.

Earlier warnings

A forwarding rule that appeared overnight gets noticed the next morning — not the week a wire transfer goes missing.

Answers you can trust

Every conclusion states what was checked and what was not. You will never get an all-clear built on a log we could not read.

This is the same philosophy behind everything we build: put practical AI where the work actually happens, keep it inside systems we own and operate, and be honest about its limits. Guardian watches one person at a time because that is the only scope at which the question “is anything wrong here?” has a real answer.

Every person you employ is an attack surface.

We think every one of them deserves something watching out for them by name. If you would like to see what a Guardian would find on your tenant, we are happy to show you.

About Vulcan365: We provide Microsoft 365, Azure, managed IT, and custom software services for businesses in Birmingham, Alabama and beyond. Guardian runs inside Impact, the platform we built to run our own managed services business.

Related reading: We Built Our Own Accounting System. Then We Put Agents Inside It.  ·  FabrCore, our open-source .NET agent framework.

We Built Our Own Accounting System

What happened when we put AI agents inside our own books.

Unlocking Microsoft 365 for Your Dental Practice

The Microsoft 365 features dental practices pay for but never switch on.

Microsoft Teams for Dental Offices

How dental teams coordinate care without HIPAA risk.

Browse all articles · See our managed IT services