Skip to main content
Docs navigation

Quickstart

Connect one Linux host, run linux.uptime through policy, then point your LLM at the same catalog. About five minutes.

Before you start, you need:
  • 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.
  • sudo on that host.
  • Allow outbound HTTPS to emisar.dev:443 for the runner, installer, and release files, and to registry.emisar.dev:443 for 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:

shell
$ 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.

Linux
      # 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 emisar system user, puts the binary at /usr/local/bin/emisar, and installs a hardened emisar.service unit (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.yaml and the enrollment key to /etc/emisar/runner.env (mode 0600). State and logs live under /var/lib/emisar and /var/log/emisar;
  • installs the host-matched starter packs (on a typical Linux host: linux-core, debugging, and systemd-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:

shell
$ 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. A 401 means the enrollment key was already used, expired, or revoked. Create a new key and run the installer again.
  • A 409 means 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 set runner.id in this host's config to register under a declared name.
  • A 402 means 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:

output
 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__*" to permissions.allow in ~/.claude/settings.json.
  • Gemini CLI — set "trust": true on the emisar server in ~/.gemini/settings.json.
  • Grok CLI — add "MCPTool(emisar__*)" to [permission].allow in ~/.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:

  1. The agent investigates through emisar and finds the root cause — reads run on policy, so this part is unattended and on the record.
  2. 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.
  3. 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.

What you just set up

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.

Last reviewed September 7, 2026