Docs navigation
Get started
AI agents
Connect
Operate
Day to day
When it breaks
Govern access
Team & account
Access
Identity concepts
Provider guides
Account
Quickstart
Connect one Linux host, run linux.uptime
through policy, then point your LLM at the same catalog. About five minutes.
- A Linux host with systemd — a VM, a cloud instance, or bare metal. The installer sets up a systemd service; for containers, see Install in a container.
-
sudoon that host. -
Allow outbound HTTPS to
emisar.dev:443for the runner, installer, and release files, and toregistry.emisar.dev:443for action packs.
1. Create your account#
Sign up to create your account. It's your control plane: runners connect to it, your LLM's MCP calls arrive there, and it applies your policy and writes the audit trail. The free plan covers 3 runners and 1 user. No credit card required.
2. Install the runner#
The runner is a small service that lives on your host and executes actions there —
nothing touches the host except through it. In the console, click Runners → Connect a runner. You'll get a one-line install command
with a single-use enrollment key
(emkey-enroll-…, shown once
— copy it now). Run it on the host you want to give your LLM access to:
$ curl -fsSL https://emisar.dev/install.sh \
| sudo EMISAR_ENROLLMENT_KEY=emkey-enroll-… bash
Verify this download first
The installer runs these checks before the binary can run as sudo. Bundle verification uses GitHub CLI with gh attestation verify --bundle; without it the installer asks before continuing on the checksum alone, or warns and continues when run unattended. GitHub CLI needs no GitHub login, but a fresh cache loads public trust roots from the hosts listed under Network requirements.
# signed checksum metadata — produced for this tag by the trusted workflow
$ gh attestation verify SHA256SUMS --bundle SHA256SUMS.sigstore.jsonl \
--repo andrewdryga/emisar \
--signer-workflow AndrewDryga/emisar/.github/workflows/runner-release-trusted.yml \
--source-ref refs/tags/runner-v<version> \
--deny-self-hosted-runners
✓ Verification succeeded!
…
# archive bytes — match the authenticated checksum
$ awk -v file='emisar-<version>-linux-amd64.tar.gz' \
'$2 == file { print; found=1 } END { exit !found }' SHA256SUMS \
| sha256sum -c -
emisar-<version>-linux-amd64.tar.gz: OK
…
More on the signing pipeline: Release integrity.
What does the install script do?
It's a plain shell script, and you can read it first if you'd rather. It:
- — checks the archive against its SHA-256 checksum and, when GitHub CLI is installed, authenticates the signed checksum first;
-
—
creates an unprivileged
emisarsystem user, puts the binary at/usr/local/bin/emisar, and installs a hardenedemisar.serviceunit (Restart=on-failure). Without systemd it stops and points you at--no-service. On macOS it installs a LaunchDaemon instead — fine for a laptop; production runs on Linux; -
—
writes the settings to
/etc/emisar/config.yamland the enrollment key to/etc/emisar/runner.env(mode 0600). State and logs live under/var/lib/emisarand/var/log/emisar; -
—
installs the host-matched starter packs (on a typical Linux host:
linux-core,debugging, andsystemd-deep); - — starts the service, which connects out to the control plane.
The installer also adds starter packs. A pack is a set of ready-made actions for one tool — Linux basics, nginx, Postgres, etc. Pack actions are the tools your agent gets, so add more later for whatever else the host runs: see Use a published pack.
3. Watch it connect#
The console updates on its own: your host appears under Runners, online, advertising the actions it can run. You can also check from the host:
$ sudo emisar status
✓ connection connected · heartbeat sent 3s ago
✓ catalog 4 packs · 82 actions advertised · all available
✓ process PID 1842 · up 2m15s · 1 connection attempt(s)
✓ runs 0 in flight (last reported by the daemon)
✓ checks 7 local readiness checks passed
Runner is connected and healthy.
That is the host's own view. The console has the final say on whether the runner is really connected.
The stock linux-core
pack is trusted automatically because its hash matches the one emisar publishes. A
custom or edited pack waits for a trust decision instead — that flow is in Roll out and roll back packs.
The runner is not showing up
Work through these on the host, in order:
-
—
systemctl status emisar— check the service is running. If it is not, start it and read the error. -
—
sudo journalctl -u emisar -n 200— the log shows what failed. A401means the enrollment key was already used, expired, or revoked. Create a new key and run the installer again. -
—
A
409means another runner already holds this name. A runner's name defaults to its hostname and cannot be renamed, so this is what a rebuilt host or a restored image looks like. Delete the existing one under Runners to free the name, or setrunner.idin this host's config to register under a declared name. -
—
A
402means the account is at its plan's runner limit — three on the free plan. Delete a runner you no longer use, or move to a larger plan. -
—
A connect that hangs instead of failing is a blocked path, not a bad key. Allow
outbound HTTPS to
emisar.dev:443. -
—
sudo emisar doctor— checks the config, credentials, packs, and action binaries in one pass.
More symptoms and fixes: Troubleshooting.
4. Run your first action#
Open the runner you just added from Runners. Select the linux.uptime
action. Add a short reason, then click Dispatch. The output streams back:
14:32:07 up 18 days, 4:01, load average: 0.42, 0.51, 0.48
linux.uptime
is low risk, so the default policy runs it without approval. A
high-risk action would stop for human approval instead. You set what each risk tier does
in your policy. The cloud
audit and runner journal record the run and its reason. See
Run an action
for the full console workflow.
5. Point your LLM at it#
This is the step everything above was for: connect your AI agent, and the catalog becomes
tools it can call — reads run at once, risky work waits for your approval. In the
console, open
AI agents
and select your client. Claude.ai and ChatGPT connect over remote MCP with OAuth, and the page walks you through it. Local and CLI clients use the
emisar-mcp
bridge. Install it on the machine where your client runs:
$ curl -fsSL https://emisar.dev/install-mcp.sh | sudo bash
The installer finds supported clients, opens a browser approval, and adds emisar to each client you select. For manual setup, see Connect a local AI client.
Restart your AI client, then ask it
"list my emisar runners and check the load on each one."
You are done when it returns the result from linux.uptime
and the run appears in Runs.
Stop your AI client asking permission for every emisar action
Most clients ask "allow this tool?" the first time a model calls one. That prompt is redundant for emisar's tools, because emisar gates every action server-side: account policy applies to every call, risky actions wait for human approval, and out-of-policy ones are denied.
The installer offers to do this for Claude Code, Gemini CLI, Codex CLI, and Grok CLI —
the four clients whose setting can name the
emisar
server alone. It leaves Cursor alone, because Cursor's only control is global.
Whichever way you answer, auto-permitting in a client never bypasses emisar's gate. To
set it yourself:
-
—
Claude Code
— add
"mcp__emisar__*"topermissions.allowin~/.claude/settings.json. -
—
Gemini CLI
— set
"trust": trueon theemisarserver in~/.gemini/settings.json. -
—
Grok CLI
— add
"MCPTool(emisar__*)"to[permission].allowin~/.grok/config.toml. -
—
Cursor, Codex CLI
— Cursor approves globally through agent auto-run. Codex can trust only emisar with
default_tools_approval_mode = "approve"under[mcp_servers.emisar]. The AI agents page has the exact per-client steps.
6. The workflow we recommend#
emisar gives an agent eyes and hands on production, restrained by the policy you set. It can make changes — that is what a gated action is for — but don't use it as your configuration manager. Standing changes an agent makes on a live host are how you get drift nobody can reproduce.
So the durable pattern pairs the agent with your infrastructure-as-code:
- The agent investigates through emisar and finds the root cause — reads run on policy, so this part is unattended and on the record.
- If it's on fire, it hot-patches through one gated action to contain it — a person approves, and the side effect waits until they do.
- Then it writes the durable fix as code — Terraform, Ansible, a Kubernetes manifest, whatever your fleet runs — and hands you a change you review and apply through your normal pipeline. The hot-patch bought time; this is the part that survives the next converge.
And cover as much of your infrastructure as you can: the more actions an agent can reach, the more it can do for you, and breadth is safe because policy decides what actually runs. Adding runners and matching packs to each host is in Manage the runner fleet.
We also recommend running your agents locally inside a sandbox, such as co:op. Agents are most useful when you can leave them working unattended, but built-in permission prompts alone don't isolate them from your machine. An agent with access can leak your secrets, use your SSH keys without asking, or delete files it shouldn't touch.
A sandbox limits which files, secrets, and tools the agent can access on your machine. It pairs well with emisar, which extends that control to your infrastructure and third-party tools.
See it end to end on a real incident: the 33-hour wipe.
There is now a finite, reviewed catalog between an AI agent and your host: the model can call only declared actions, risky calls wait for a person, and configured patterns redact matching output on the host. The audit records who ran what, and why.
Next, add a published pack for a service you operate.