AI agents have gotten genuinely good at operations work. Point one at a misbehaving service and it will read the logs, correlate the metrics, form a hypothesis, and tell you what it thinks is wrong — often faster than you would. The hard part was never the reasoning. It's the access: how do you let a model touch production without handing it the keys to set the building on fire?
The tempting answer is to give it a shell. It's one line of config, and the agent already knows how to use SSH. It's also the answer you'll regret. Below is the pattern that actually holds up under a security review — and under a live incident.
Why a shell is the wrong door
A shell is unbounded by construction. The moment an agent has ssh you@prod, it can
run anything the account can run, and "anything" includes the commands you never meant it to
reach. A model that is even slightly wrong — or one that's been
prompt-injected
by a malicious log line it just read — can turn a request to "clean up old data" into a
DROP
on the wrong database. There is no gate before the action, and no trustworthy
record after it. We wrote a longer
breakdown of the SSH risks
if you want the full version.
The fix isn't to make the agent "more careful." Careful is not a control. The fix is to change the shape of what the agent can ask for in the first place.
The pattern that holds: a gated catalog
Borrow the idea from how you already ship code. You don't give your CI system a root shell on prod; you give it a reviewed artifact, an explicit gate, and a durable history. Apply the same three ideas to every operational command an agent is allowed to request. Concretely, that's four properties working together.
1. A declared, typed catalog of actions
Instead of a shell, the agent gets a list of declared
actions: read service
logs, check replication lag, revert this deploy. Each one is
defined ahead of time with typed arguments and validation — a unit name must match a pattern, a
namespace must be in an allowed set. The agent literally cannot request a command that isn't in
the catalog, because it can't see one. This is the single most important property: it converts
"what could the model possibly do?" from an open question into a finite, reviewable list.
2. A policy gate in front of every call
Declaring an action doesn't mean auto-running it. Each call passes a policy that returns allow, require approval, or deny. The obvious default is to tier by risk: reading logs and metrics runs freely, because a read can't hurt you; a write that mutates state stops. You set this once, then add narrower overrides — a specific destructive action denied outright, a whole family of actions routed to approval.
3. Human approval for the handful of risky writes
The reads are where the agent spends almost all its time, and they run without you. The rare mutating action — restart this, revert that, terminate the wedged backend — is the one moment a human steps in. A good approval shows the actor, the exact arguments, the target host, and the policy rule that triggered the gate, so the decision takes one read and one click. That's the whole trade: the agent moves fast on everything safe, and you stay in the loop for the few things that aren't.
4. A complete audit of everything
Every call — allowed, approved, or denied — lands in an audit trail with its inputs, outputs, exit code, and who asked. For this to be worth anything during an incident, it has to be hard to quietly edit. A hash-chained journal on the host, mirrored to a searchable system of record and streamable to your SIEM, means a missing or altered line is detectable rather than invisible. The audit is what turns "the AI did something" into "here is exactly what it did, and why."
5. Don't trust the control plane either
The four properties above assume the thing issuing actions is trustworthy. A serious design assumes it might not be. The strongest version of this pattern lets the host verify for itself: a local allow/deny list the host enforces regardless of what the cloud says, and a signature on each dispatch that's minted on the operator's own machine. A compromised control plane can then relay a signed request but never forge, alter, or originate one. The host gets the last word. We go deep on this in the security model.
This is just Zero Trust, applied to agents
If this feels familiar, it should. It's the same control set Anthropic describes in Zero Trust for AI Agents: least agency (the agent sees only declared tools), deny-by-default, human approval for high-risk actions, and an immutable audit trail. The declared catalog is least agency. The policy gate is deny-by-default. The approval step and the audit are the other two. See the control-by-control mapping if you want to check the work.
Where emisar fits
emisar is one implementation of this pattern, built as an MCP server so any agent — Claude, Cursor, ChatGPT — connects to it the same way it connects to any other tool. You install a small runner on each host, choose which packs of actions it exposes, set your policy, and point your agent at it. The runner dials out (no inbound port on your hosts), re-validates every argument, redacts secrets before output leaves the machine, and writes the hash-chained journal. You don't have to use emisar to follow the pattern — but if you don't want to build and maintain all five properties yourself, that's the trade it's making.
Start small
You don't have to hand over your whole fleet on day one. Start read-only: give an agent the logs-and-metrics actions on one non-critical service and watch how it investigates. Add the first gated write only when you trust the loop. The point of the pattern is that you can grow the agent's reach one declared action at a time, with a gate and a record at every step — instead of the all-or-nothing of a shell. When you're ready, the quickstart takes about five minutes.