emisar is built to scratch our own itch. We like shipping fast with an AI agent, and we know what that approach can do when it goes wrong.
Sandboxing the model did not solve this. Sandboxing constrains where a model runs; it does not constrain a remote SSH session. Once you hand an agent a shell on a production host, it has whatever that shell has.
The approach we trust is to whitelist what the agent can do. The toolset is defined before the agent asks for anything. Models are most useful in yolo mode, and we wanted to keep the experience of stepping away and coming back to a finished job without handing over a shell.
The design separates a control plane that governs policy and serves as the cloud portal, a runner that executes with minimal trust in the portal, and an MCP interface agents can use from wherever they run. The control-plane and runner split was inspired by Firezone.
What the agent can do
An agent acting through emisar can invoke actions. An action is declared in a pack. Here is a trimmed excerpt of a real one:
id: linux.systemctl_restart kind: exec risk: high args: - name: unit type: string required: true validation: pattern: "^[A-Za-z0-9@._:][A-Za-z0-9@._:-]{0,127}$" max_length: 128 execution: command: binary: systemctl argv: ["restart", "{{ args.unit }}"] timeout: 60s output: max_stdout_bytes: 4096 max_stderr_bytes: 8192
Actions are grouped into packs. A pack contains its manifest, action definitions, and any scripts those actions use. The version gives people a release name; the content hash identifies the exact bytes installed on the runner and approved by an operator. If an action, validation rule, or script changes, the hash changes and the new pack must be trusted separately.
Anything not described by an installed and trusted action is not expressible through emisar. If an operator deliberately installs an action capable of dropping a database, however, the agent can request that action. emisar does not make a permitted destructive operation harmless.
Following one request
This is an intentionally simplified example. A real incident usually takes tens of tool calls to inspect the service, read logs, check related systems, try a fix, and verify the result. Here we reduce the investigation to three calls so the request path is easy to follow. Identifiers are shortened throughout; real requests use the exact pack and runner references returned by discovery.
The first call reads recent warnings from checkout.service:
{
"action_id": "linux.journalctl",
"pack_ref": "linux-core@0.3.19/sha256:8d0ba17c…701c70ba",
"runner_refs": [
"api-iad-02~18a65e2f…6d2fc9"
],
"args": {
"unit": "checkout.service",
"since": "30m",
"priority": "warning"
},
"reason": "Read recent checkout warnings before changing the service.",
"expected": "Find why checkout stopped making progress."
}
The log text below is hypothetical; the response shape is the real one. In this example the read succeeds and returns two warnings:
{
"operation_id": "op_01K09E3N8Y4J6T2D5Q7R1V9WBE",
"runs": [{
"run_id": "019f61cf-59b4-71d9-a78c-4ece74d1e162",
"runner_ref": "api-iad-02~18a65e2f…6d2fc9",
"status": "success",
"exit_code": 0,
"stdout": "Jul 22 14:31:08 worker pool stalled for 120s\nJul 22 14:31:09 readiness check failed"
}]
}
The next call requests the restart. Its evidence
points to the log run and records what the agent found:
{
"action_id": "linux.systemctl_restart",
"pack_ref": "linux-core@0.3.19/sha256:8d0ba17c…701c70ba",
"runner_refs": [
"api-iad-02~18a65e2f…6d2fc9"
],
"args": {"unit": "checkout.service"},
"reason": "Restart checkout to reset its stuck worker pool.",
"evidence": "Run 019f61cf-…-e162 returned repeated worker pool stalled warnings.",
"expected": "Unit returns to active; checkout health check passes."
}
The pack_ref
identifies the pack by a content hash over the pack tree. The runner_refs
identify the targets. The reason, evidence, and expected result travel with the request into the
audit record.
The control plane checks identity, scope, pack trust, and policy. It records the decision in the cloud audit, dispatches allowed requests, and holds requests that need approval. An approved request is checked again before dispatch.
The runner opens an outbound TLS WebSocket to the control plane and listens on no inbound port. An eligible dispatch arrives over that connection.
The runner does not rely on the control plane's validation. It looks up the action locally,
hashes its copy of the pack, and compares the result with the requested pack_ref. It
applies local admission rules, rejects arguments it does not recognize, validates the supplied
values, and clamps requested limits to the action's declared envelope.
It then renders the argument vector from the template stored in the pack. For this action, it
executes systemctl restart checkout.service
directly. There is no shell between the runner and the binary.
The child process receives a minimal environment and runs with the OS permissions of the runner service user. Standard output and standard error are bounded and pattern-redacted before anything leaves the runner. If the timeout expires or the operation is cancelled, the runner terminates the process group.
A selected view of the completed result looks like this:
{
"operation_id": "op_01K09E3N8Y4J6T2D5Q7R1V9WCF",
"runs": [{
"run_id": "019f61cf-59b4-71d9-a78c-4ece74d1e163",
"runner_ref": "api-iad-02~18a65e2f…6d2fc9",
"status": "success",
"exit_code": 0,
"duration_ms": 380
}]
}
Empty output streams are omitted rather than returned as empty strings.
Exit code 0
says that systemctl restart
completed. The final call checks the service state instead of assuming the restart fixed the
incident:
{
"action_id": "linux.systemctl_status",
"pack_ref": "linux-core@0.3.19/sha256:8d0ba17c…701c70ba",
"runner_refs": [
"api-iad-02~18a65e2f…6d2fc9"
],
"args": {"unit": "checkout.service"},
"reason": "Verify checkout recovered after the restart.",
"evidence": "Restart run 019f61cf-…-e163 completed with exit code 0.",
"expected": "systemctl reports checkout.service active."
}
For this example, the status action returns:
{
"operation_id": "op_01K09E3N8Y4J6T2D5Q7R1V9WCH",
"runs": [{
"run_id": "019f61cf-59b4-71d9-a78c-4ece74d1e164",
"runner_ref": "api-iad-02~18a65e2f…6d2fc9",
"status": "success",
"exit_code": 0,
"stdout": "● checkout.service — Checkout API\n Active: active (running)"
}]
}
A nonterminal response includes a continuation object describing the next call. The
operation_id
allows a client to recover an operation after losing a response. Separately, the runner keeps a
replay record so the same accepted dispatch cannot start another process during its retention
window.
Audit, redaction, and privileges
The control plane keeps the fleet-wide audit. A runner that receives a dispatch also writes to a local hash-chained JSONL journal before starting the process and again when it reaches a terminal outcome. The chain makes edits, deletions, and reordering detectable. An attacker with enough privilege on the host can replace the whole file.
Redaction removes values that match configured patterns. A secret in an unexpected format can still appear in output.
The runner's OS privileges limit what a permitted action can affect. A permitted destructive action remains destructive when it runs. emisar is not a VM, container, or kernel sandbox.
A compromised host already controls that host. emisar also does not run the agent loop: the agent decides what to request, while emisar decides whether that request is available and allowed.
Local admission can make a runner stricter than the control plane through action allow and deny patterns and a maximum accepted risk.
The MCP surface
emisar exposes twelve fixed MCP tools.
Discovery uses list_packs, find_actions, and get_action. Execution uses run_action. Other tools handle waiting,
operation recovery, recent runs, and runbooks.
Packs add actions to the catalog. They do not add more MCP tool definitions.
Signed dispatch
In normal mode, the runner trusts the hosted control plane to authenticate callers, evaluate policy, and send eligible work.
Signed dispatch is optional. The operator's MCP bridge signs the exact action, pack, arguments, targets, reason, operation, nonce, and time with a key the cloud does not hold. An enforcing runner verifies that signature before execution.
The cloud can still delay or drop a dispatch. It cannot forge a new request, change its arguments, widen its targets, or successfully replay it. The terminal result is not a CA-signed receipt.
Private packs
Packs can also wrap internal workflows.
Our private emisar-admin
pack is not published in the public catalog. It runs only on dedicated administration runners
beside the portal and calls named operations through a fixed release-RPC script.
For example, emisar.admin.access.diagnose
is a low-risk, read-only action. Given an account and member, it returns the account and
membership details, confirmation and MFA state, active session count, and active API-key count.