Eitri is a self-hosted, single-binary AI coding agent for Linux. It runs entirely on your machine and your own model credentials — no vendor lock-in, no hosted agent service, nothing leaves your box except the requests you choose to send to your provider.
- Your data stays yours. Sessions, transcripts, and configuration live under
~/.eitri. You control where they are and who can read them. - One binary. No runtime, no daemon, no container image — a single static Go binary you can drop anywhere.
- Your provider, your terms. Point Eitri at any model or OpenAI-compatible endpoint, from a local model to a cloud provider.
- Sandboxed by default. Eitri never runs unsandboxed: every execution is confined by bubblewrap.
Eitri's internal, agent-facing documentation lives in
CONTEXT.md. This README is for humans.
# Install the declared toolset (required; Eitri refuses to start without it,
# because its agent prompt promises these tools unconditionally):
# Debian/Ubuntu: sudo apt install bubblewrap bash ripgrep curl lynx patch python3 git
# Fedora: sudo dnf install bubblewrap bash ripgrep curl lynx patch python3 git
# Arch: sudo pacman -S bubblewrap bash ripgrep curl lynx patch python3 git
make build # 1. build ./bin/eitri
./bin/eitri # 2. launch the interactive TUI
# 3. on first launch you'll be asked to log in to your provider| Command | What it does |
|---|---|
eitri |
Launch the interactive TUI |
eitri -b "<prompt>" |
Run once in batch mode and exit |
eitri -v |
In batch mode, print the model's thinking/reasoning to stdout |
eitri -d |
Debug mode: write full HTTP traces to/from the provider |
eitri --version |
Print the version and exit |
If the workspace root (the directory you launch Eitri from) contains an AGENTS.md, Eitri reads it and carries its content to the model as a dedicated system-layer directive headed ## Repository instructions (AGENTS.md) — both in the TUI and in batch (-b) mode. The injected instructions are additive: the built-in Eitri persona prompt is preserved unchanged, and the message is excluded from persisted session history so it isn't duplicated on the next turn. Without an AGENTS.md, no extra message is sent and the request is byte-identical to the pre-feature case. There is no opt-in or escape-hatch flag; the file is loaded whenever it exists.
Use pprof for performance symptoms: slow rendering, stalls while streaming, high CPU, or unexpected allocation pressure. It is disabled by default; enable it only for a diagnostic run and bind it to localhost:
eitri --pprof 127.0.0.1:6060From another shell, collect profiles while reproducing the problem:
go tool pprof -seconds 30 http://127.0.0.1:6060/debug/pprof/profile
curl --fail --max-time 30 -o heap.pprof http://127.0.0.1:6060/debug/pprof/heap
curl --fail --max-time 30 -o goroutine.txt 'http://127.0.0.1:6060/debug/pprof/goroutine?debug=2'Mutex and block profiling are available when needed, but are off unless requested because they add overhead:
eitri --pprof 127.0.0.1:6060 --pprof-mutex --pprof-block
go tool pprof -seconds 30 http://127.0.0.1:6060/debug/pprof/mutex
go tool pprof -seconds 30 http://127.0.0.1:6060/debug/pprof/blockUse pprof to find where time or allocation pressure is spent. To prove a performance fix, measure before and after one focused change with benchmarks; see docs/render-diagnostics.md for the full diagnostics workflow.
Eitri records every session so you can review, replay, and search past work:
eitri session list # list recorded sessions (GUID, time, cycles, model)
eitri session show <guid> [--turn N] # compact per-cycle summary
eitri session talk <guid> [--turn N|N-M] # full conversation as plain text
eitri session grep <pattern> [guid|all] # find cycles whose messages matchFull detail lives in docs/sessions.md.
- Type a prompt in the composer at the bottom and press
enterto submit. - Start slash commands with
/(e.g./settingsto open settings). - Press
?for the live/helpreference, which always shows the current bindings.
| Key | Action |
|---|---|
up / down |
Navigate completion candidates; recall a prior/next prompt when the completion list is closed |
tab / enter |
Accept the highlighted completion |
esc |
Close the completion list |
tab |
Cycle block focus when the composer is empty |
enter |
Submit the draft, or toggle the focused block when empty |
shift+enter |
Insert a newline |
| Key | Action |
|---|---|
? |
Show help |
pgup / pgdn |
Scroll history |
| Key | Action |
|---|---|
ctrl+e |
Toggle expanded/collapsed view |
ctrl+x |
Narrow the right pane |
ctrl+z |
Widen the right pane |
| Key | Action |
|---|---|
ctrl+s |
Open settings |
ctrl+o |
Copy transcript to clipboard |
| Command | Action |
|---|---|
/settings |
Open the settings panel |
/copy |
Copy the transcript to the clipboard |
/new |
Start a fresh session (clears this conversation) |
/login |
Interactive provider login |
/help |
Show this help message |
| Term | Meaning |
|---|---|
expanded mode |
ctrl+e toggles all tool and chain-of-thought blocks |
block focus |
tab to focus, enter to expand one block |
drag-select |
Click and drag to select text |
right rail |
Stats, context, and model info |
The in-TUI
/helpis always available as the live reference and is the authoritative source for keybindings.
| Variable | Purpose | Default |
|---|---|---|
EITRI_DIR |
Data directory (sessions, config, transcripts) | ~/.eitri |
EITRI_CONFIG |
Config file path override | <dataDir>/config.json |
| Key | Type | Default | Meaning |
|---|---|---|---|
provider |
string | opencode-go |
Provider backend |
model |
string | deepseek-v4-flash |
Model to use |
reasoning_effort |
string | low |
Reasoning effort level |
thinking_enabled |
bool | true |
Whether the model reasons/uses thinking |
cot_collapsed_by_default |
bool | true |
Render chain-of-thought collapsed until expanded |
tool_results_collapsed_by_default |
bool | true |
Render tool results collapsed until expanded |
max_turns |
int | 250 |
Maximum turns per run |
context_overflow_recovery |
bool | true |
Summarize older history and retry once if the provider rejects an oversized request |
extra_writable_paths |
array of strings | (empty) | Additional paths the agent may write to |
theme |
string | dark |
UI theme |
rail_width |
int | 30 |
Width of the right rail/pane |
copilot |
object | (none) | GitHub Copilot device-flow credential state |
custom_openai |
object | (none) | Custom OpenAI-compatible base URL + key |
The copilot and custom_openai objects are managed by Eitri (via device-flow login and the settings panel respectively); you rarely need to edit them by hand.
- Linux (Eitri is a Linux agent).
- Declared toolset (required; fatal at boot) — Eitri verifies every declared dependency at launch and refuses to start without it, because its agent prompt promises these tools unconditionally:
- Hard substrate:
bwrap(bubblewrap — Eitri never runs unsandboxed) andbash. - Declared tools:
rg(ripgrep),curl,lynx,patch,python3,git. - Install hints (a missing tool aborts the launch naming every miss with its package):
- Debian/Ubuntu:
sudo apt install bubblewrap bash ripgrep curl lynx patch python3 git - Fedora:
sudo dnf install bubblewrap bash ripgrep curl lynx patch python3 git - Arch:
sudo pacman -S bubblewrap bash ripgrep curl lynx patch python3 git
- Debian/Ubuntu:
- Hard substrate:
- Soft dependency (optional, never gates startup) — a browser launcher (
xdg-open, backingopen_in_browser) may be absent: it surfaces only whenopen_in_browseractually runs, as a contained error. - Base toolset (assumed present) — the coreutils
bashbuilds on:grep,sed,awk,cat,nl,diff; no boot check.
make build # build ./bin/eitri
make test # run the test suite (go test ./...)
make clean # remove build artifactsSee CONTEXT.md and docs/ for the internal codebase documentation and agent guidance.