AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
Autonomous Windows system repair agent powered by AI
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
An autonomous Windows system-repair agent, with a headless Linux build.
Eir watches your machine's health, diagnoses problems with an AI model, and fixes
them — asking for approval before anything risky.
Eir is a background agent for Windows that continuously monitors system health —
event logs, failed services, disk pressure, memory, network errors — and uses an
AI model as its reasoning engine to work out what's actually wrong and *the
least-destructive way to fix it*.README 전문 보기 ↗An autonomous Windows system-repair agent, with a headless Linux build.
Eir watches your machine's health, diagnoses problems with an AI model, and fixes them — asking for approval before anything risky.
Eir is a background agent for Windows that continuously monitors system health — event logs, failed services, disk pressure, memory, network errors — and uses an AI model as its reasoning engine to work out what's actually wrong and the least-destructive way to fix it.
It runs as a pair:
EirSvc — a Windows service running as LocalSystem, so it can read
protected logs and apply fixes without a UAC prompt. It does the monitoring,
reasoning, and (approved) repairs.The two talk over a secured local named pipe (\\.\pipe\EirSvc).
The same service also builds for Linux, where it runs headless under systemd with
no tray and is driven from the command line by eirctl — see
Linux (headless). Linux is built from source; releases publish
Windows downloads only.
The name comes from Eir, the Norse goddess of healing — the agent doesn't just watch the system, it mends it. (Pronounced "air".)
┌──────────────────────────┐ ┌───────────────────────────┐
│ Eir tray app (UI) │ named │ EirSvc (LocalSystem) │
│ - status / approvals │◄──pipe──►│ - signal collection │
│ - settings / usage │ (JSON) │ - AI diagnosis │
│ - app updates │ │ - policy + execution │
└──────────────────────────┘ └─────────────┬─────────────┘
│
┌────────▼─────────┐
│ AI provider │
│ OpenCode / Claude│
│ / Codex / Cursor │
│ CLI (as user) │
└──────────────────┘
Each decision cycle (default every 10 minutes):
Architecture & design: see ARCHITECTURE.md. Release gates and the next priorities are in PLAN.md.
Everything is configurable in the Settings panel — no file editing required.
Four CLI providers (no API keys pasted into Eir):
| Provider | Cost | Web search | Notes |
|---|---|---|---|
| OpenCode CLI (default) | Local Ollama free; cloud per your OpenCode plan | Yes — CLI --auto on app-update checks | No API key in Eir — uses the logged-in opencode CLI. Pick ollama/<model> for local Ollama, or any provider/model from opencode models. |
| Claude CLI | Uses your Claude plan | Yes — CLI built-in | No API key — reuses your logged-in claude session; profile and binary auto-detected. |
| Codex CLI | Uses your ChatGPT plan | Yes — CLI built-in | No API key — reuses your codex login session; binary and model catalogue auto-detected. Launched with your desktop-user token, never as LocalSystem. |
Cursor CLI (agent) | Uses your Cursor plan | Ask-mode (read-only) | No API key — uses the logged-in Cursor agent CLI. Run agent login once. |
The monitoring loop and the app-update check both use your configured provider.
App-update checks use live web search where the provider supports it (OpenCode --auto,
Claude/Codex built-in search). Cursor runs in ask mode.
Settings includes a Test provider button that sends a real request through the service and reports its correlated result. Other UI commands also wait for their matching service outcome, so applied, rejected, disconnected, and timed-out actions are reported instead of being silently treated as queued.
Eir_<version>_x64-setup.exe from the
latest release.EirSvc
service in a protected Program Files directory and seeds the default config. It
uses the machine Evergreen WebView2 runtime (already present on most Windows
10/11 PCs with Edge); if missing, the installer downloads Microsoft’s small
WebView2 bootstrapper.ollama/<name> for local Ollama, or any provider/model from
opencode models. Claude CLI, Codex CLI, and Cursor CLI (agent)
reuse your logged-in subscriptions and need no key in Eir.Already installed? Eir updates itself automatically.
The release also provides a single-file portable tray executable. It needs no
installer or administrator rights, and uses the same Evergreen WebView2 runtime as
other desktop apps (plus no Visual C++ redistributable). It runs EirSvc under the
launching user's token for that session. One portable instance may run
per Windows session and can coexist with an installed Eir. Its config, policy, audit
database, and logs persist under %LOCALAPPDATA%\EirPortable; closing the portable UI
also stops its foreground service. Portable mode never changes Start-with-Windows and
never launches the NSIS self-updater—download a newer portable release to update it.
LocalSystem repairs and continuous background monitoring still require the full installer.
After an upgrade, open About and confirm the UI and service show the same version. Then use Settings → Test provider to exercise the saved provider through the installed LocalSystem service. In App Updates, “last run” means a cycle completed; “last clean” means the cycle recorded no source/check/app failure or deferred candidate. It is not proof that every configured package manager was available.
All settings live in the in-app Settings panel: start-with-Windows, AI provider
and models, advisor escalation, polling intervals, watched event-log
channels and directories, and app-updater settings. Provider/monitoring settings are
persisted to config.toml next to the installed service executable, or under
%LOCALAPPDATA%\EirPortable in portable mode. Provider/model changes apply live; only
collector channel, interval, or directory changes restart the installed service.
Portable mode saves those collector changes and asks you to restart portable Eir.
Updater/advisor settings also apply live.
config.toml.example documents every field for reference, but you should never need
to edit it by hand. The headless Linux build has no Settings panel; it is configured
from config.toml.linux.example (see Linux (headless)).
Requirements: Rust (stable, MSVC toolchain), Tauri CLI, and Windows. (The headless Linux build has its own steps under Linux (headless).)
# 1. Tauri CLI (once)
cargo install tauri-cli --version "^2"
# 2. (Optional) regenerate the icons
powershell -NoProfile -File icons\gen-icon.ps1
# 3. Build the installer. This runs build-svc.ps1 first (which compiles EirSvc
# and stages bin\eir-svc.exe), then bundles the tray app + service into NSIS.
# WebView2 uses the machine Evergreen runtime (downloadBootstrapper if absent).
cargo tauri build --config eir-ui/tauri.conf.json -- --locked
Run the repository gate (including manifest/Cargo.lock version agreement and locked Rust builds):
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\verify.ps1
e2e/ is a WebdriverIO + tauri-driver suite that drives the real debug
eir.exe + eir-svc.exe through the real webview and named pipe — boot,
"What Eir noticed" from a real injected error dialog (with Dismiss and Clear),
Explain, Investigate & fix, settings persistence across a restart, and a clean exit. It runs fully
isolated from an installed Eir: a random portable pipe
(EIR_PORTABLE=1 / \\.\pipe\EirSvcPortable-<random>), its own temp state
under an overridden LOCALAPPDATA, and a fake claude_cli binary
(e2e/fixtures/fake-claude.cmd) that never contacts a real model and always
reports zero problems, so the real fix executor can never act on the machine
running the suite. See e2e/service.ts for how the isolation is enforced.
Requirements: tauri-driver (cargo install tauri-driver --locked) and a
msedgedriver matching the installed WebView2 Runtime version (Microsoft
signature verified before use).
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\run-e2e.ps1
It's also its own step in scripts\verify.ps1 (after cargo test) and in
CI's windows-latest job. scripts\run-e2e.ps1 never downloads either
WebDriver tool itself — it only locates and verifies what's already on the
machine. CI has nothing pre-installed, so it provisions both itself first:
scripts\setup-tauri-driver.sh (a pinned, hash-verified tauri-driver) and
scripts\setup-msedgedriver-ci.ps1 (a WebView2-version-matched,
Microsoft-signature-verified msedgedriver).
For v0.34.6 and later, the tag workflow also requires the exact tag
v<manifest-version>, reruns its gates from that tag SHA, and keeps the release draft
until the exact installer .sig and latest.json version, URL, and signature agree.
eir-svc also builds and runs as a headless guardian on Linux under systemd — no
tray, no named pipe. The decision loop, policy gate, approvals, learning, audit DB,
and Ask/Investigate are the same OS-neutral code as Windows; every OS-facing edge
(collectors, executor, AI-CLI launch, control-plane transport) has a Linux
implementation alongside the Windows one. eir-ui (the Tauri tray) is never built on
Linux — control is entirely through eirctl, a small companion CLI (workspace
directory eir-cli, Cargo package and binary eirctl) that talks the exact same
UiRequest/ServiceMsg JSON-line wire protocol as the Windows tray, over a Unix
domain socket instead of a named pipe.
There are no Linux release downloads: build it from source as below. It has been
built and run on Ubuntu 26.04, and CI builds and tests it on Ubuntu on every push to
master.
What's different from Windows:
journald (polled, not streamed) replaces the Windows Event Log;
/proc, systemctl, and ip -j addr show replace WMI/registry reads. There is no
Linux analogue of the Windows Firewall/Defender/Windows-Update fields — they stay at
their "unknown" defaults and are left out of what Ask and Investigate tell the AI.
Watching arbitrary log directories is not implemented on Linux yet; the journal is
the log source.service_restart/service_stop/service_start (via systemctl),
log_cleanup, disk_cleanup (apt-get clean / journalctl --vacuum-time / a
bounded /tmp purge), process_kill (exact-name, via /proc), and file_delete
have real Linux implementations. Every other FixAction (registry, scheduled tasks,
drivers, BCD, Windows Firewall/Defender, SFC/DISM, startup entries) is hard-blocked
on Linux, both in the AI's own prompt and in policy.linux.toml.eirctl approve first, unlike
Windows' whitelisted service_restart/stop/start. Add action names to the
[whitelist] in /etc/eir/policy.toml to opt in.
See CONTEXT.md's decision entry for why.policy.toml guards
systemctl stop/restart (never start, which is not disruptive) on core system
units — a compiled list (ssh.service, tailscaled.service, systemd-*, docker,
eir.service itself, …) plus an optional, additive, host-specific drop-in at
/etc/eir/protected-units.d/*.conf (one glob per line; ships empty by default).eir-svc runs as root (the systemd unit's default),
it never launches the AI CLI as root. [api] linux_ai_user names the local, non-root
account whose CLI login is used; the CLI child keeps only that account's primary
group (docker, sudo, adm and every other supplementary group are dropped) and runs
with no-new-privileges, so even a passwordless sudo rule cannot raise it. An ordinary
admin login is therefore fine. Leaving it unset disables the AI subsystem rather than
running the CLI as root — collectors, the executor and approvals still run.# 1. Build (from this repo, on Linux). Package names, not directories: the
# eir-cli directory holds the `eirctl` package. Never --workspace — the Tauri
# tray (eir-ui) is Windows-only.
cargo build --release --locked -p eir-svc -p eirctl
# 2. Install the binaries, config and policy
sudo install -m 755 target/release/eir-svc /usr/local/bin/eir-svc
sudo install -m 755 target/release/eirctl /usr/local/bin/eirctl
sudo mkdir -p /etc/eir /etc/eir/protected-units.d # /var/lib/eir: eir.service's own StateDirectory= creates it
sudo install -m 640 config.toml.linux.example /etc/eir/config.toml # then edit it
sudo install -m 640 policy.linux.toml /etc/eir/policy.toml
# 3. Install and start the service
sudo install -m 644 packaging/systemd/eir.service /etc/systemd/system/eir.service
# The AI CLI writes its scratch workspace and login state in linux_ai_user's home,
# which the unit's sandbox (ProtectHome=read-only) otherwise blocks. This example is
# for the Claude CLI as `ubuntu`; list your CLI's own state instead (~/.codex for
# Codex, ~/.local/share/opencode for OpenCode, ~/.cursor for Cursor), always keeping
# ~/.cache, where Eir puts each call's scratch workspace:
sudo mkdir -p /etc/systemd/system/eir.service.d
printf '[Service]\nReadWritePaths=/home/ubuntu/.cache -/home/ubuntu/.claude -/home/ubuntu/.claude.json\n' \
| sudo tee /etc/systemd/system/eir.service.d/10-ai-user.conf # use your linux_ai_user's home
sudo systemctl daemon-reload
sudo systemctl enable --now eir
systemctl status eir
At minimum, edit /etc/eir/config.toml's [api] section: set provider and
linux_ai_user to a real, already-logged-in local account (e.g. claude login /
codex login / opencode auth login run once as that user). Then drive it with
eirctl (as that user, or any uid/gid listed in [service] socket_allow_uids/
socket_allow_gids — root is always allowed):
eirctl status # live metrics, failed units, recent signals and fixes
eirctl approvals # actions awaiting a human decision
eirctl approve <id> # or: eirctl reject <id>
eirctl pause # pause monitoring
eirctl resume # continue monitoring
eirctl ask "what is eating memory right now"
eirctl investigate "check for anything unusual" # fixes still go through policy
--json prints status or approvals as the raw JSON payload, for scripts.ask and investigate wait up to five minutes for the answer (--timeout <secs>
changes that). An investigation's fixes follow the same policy as any other, so on
a default Linux install they wait in eirctl approvals.0 done, 1 the service refused the request, 2 usage error, 3
could not connect, lost the connection or timed out.$EIR_SOCKET when the service uses a non-default [service] socket_path.Running without root or systemd. EIR_RUNTIME_ROOT=<dir> eir-svc run reads
config.toml and policy.toml from <dir> instead of /etc/eir, and resolves a
relative audit_db there too. This exists for testing, and also lets an ordinary user
run Eir where systemd is unavailable (for example in a container): point [service] socket_path at a directory that user can write, and set EIR_SOCKET to match for
eirctl. Run that way the AI CLI runs as that same user (there is no privilege to
drop), fixes that need root such as systemctl restarts or journal and apt clean-ups
fail, and collectors that need systemd or a missing tool (the journal, failed units,
and network interfaces where ip is absent) report errors; CPU, memory and disk
monitoring, Ask and Investigate still work.
| Crate | Layer | Responsibility |
|---|---|---|
eir-proto | shared | Wire types for the UI ↔ service pipe/socket protocol. |
eir-svc | service | Windows LocalSystem service or Linux systemd service: signal collection, AI client, policy, execution, audit DB. |
eir-ui | presentation | Tauri tray app; static frontend in ui/. Windows only. |
eir-cli (package and binary eirctl) | presentation | Linux control CLI over the Unix control socket; a stub that exits on Windows. |
\\.\pipe\EirSvc.eir-svc.exe is an ordinary, single-link
file directly under a protected Program Files directory. Install and upgrade reject
redirected paths, copy legacy state from a held source stream into a fresh protected
file, reset ownership/ACLs on Eir-owned files, and restore the previous service after
an interrupted in-place upgrade. Uninstall removes only validated Eir state without
following reparse points.EirSvc. Portable clients deliberately cannot
control the privileged service. No network listener is opened.ProtectSystem=strict, ProtectHome=read-only, NoNewPrivileges; writable paths
are limited to its own state and runtime directories, /var/log, the apt cache and
the AI user's CLI directories you add). eirctl connects over a Unix
socket (/run/eir/eir.sock); the service checks the connecting process's kernel
credentials (SO_PEERCRED) before reading anything and accepts only root or a
uid/gid listed in [service] socket_allow_uids/socket_allow_gids. The socket file
is deliberately connectable by anyone so that check, not file permissions, is the
gate. No network listener is opened. The AI CLI never runs as root (see the Linux
section above), and core units such as and cannot
be stopped or restarted by Eir whatever says.MIT © Swatto
winget-managed
apps update in a single batch; apps no package manager tracks are handled by the
AI: it finds the official installer via web search, and Eir validates it
(https-only, trusted-host/vendor-domain gating, .exe/.msi only, size-bounded
download, SHA-256 + Authenticode recorded), installs it silently, and verifies
the new version is actually installed. Each result is shown as Current / Verified /
Installed (unverified) / Failed / Skipped, with method, versions, and available
signature or failure evidence; recent attempts retain category, exit code, detail,
and time. Partial inventories, deferred checks, and failed empty runs are shown as
warnings with their notes, never as “No updates found”. One ⬆ Update everything
button does the lot; per-app notes still let you correct or silence false positives
for your own self-built apps. Machine-wide winget updates are installed by the Eir
service itself, so installers such as Visual Studio's no longer ask for UAC approval;
per-user updates run as you, where they need no elevation. An app whose update fails
in two runs in a row is paused (2 days, then 4, then a week) instead of failing every
day; its row says when Eir will next try and why it failed, and Retry tries it
straight away. Apps installed only for your user account (typically ones that keep
themselves up to date, including Tauri and Electron apps) and apps that report no
installed version (such as Battle.net) are updated only by winget or by the app
itself, and each run's notes name them.require_tray = false is set for a headless PC. The tray app can start with Windows and launch hidden.journalctl -u eir.~/.cache and other cache folders,
/tmp, /var/tmp and /var/crash count as low-risk, while Documents, Desktop,
Pictures, Downloads, Videos and Music in a home directory are flagged as
personal data.eirctl has no
commands for learned facts or Ignore/Always Approve preferences (learning itself
still runs). Settings live in /etc/eir/config.toml; after editing it, run
sudo systemctl restart eir.ssh.servicetailscaled.servicepolicy.toml