Installing EONYX: build, run, and configure
EONYX is a terminal AI agent for working with code, written in Go. It connects directly to any OpenAI-compatible API (OpenAI, OpenRouter, DeepSeek, Moonshot, local Ollama / llama.cpp / LM Studio) — no external services, no telemetry, no OAuth. One process, one binary, everything local. Here: installation, the first run, and the full configuration.
1 Requirements and installation
1.1 What you need
- Go 1.26+ — to build from source (prebuilt binaries don’t need it).
- An API key for any OpenAI-compatible provider — or a local model server (Ollama, llama.cpp, LM Studio), in which case no key is needed.
- A terminal: Windows Terminal / PowerShell, any Linux shell, macOS Terminal.
1.2 Installation options
git clone https://github.com/avtotor/eonyx
cd eonyx
make build # builds bin/eonyx with the version from the git tagOr install into $GOPATH/bin:
make installThe version is baked into the binary at build time (git describe --tags) — there are no hardcoded versions in the code:
eonyx --versionv* git tag — download the archive for your platform from the Releases page and put the binary in your PATH. Linux, macOS, and Windows are supported.1.3 First run
cd my-project
eonyxAn interactive TUI chat opens. If there is no configuration at any level yet, EONYX creates a working eonyx.json in the global directory itself — with two DeepSeek models and one local one (Ollama). All that’s left is to set the key:
export DEEPSEEK_API_KEY=sk-... # or your own provider, see belowThe run subcommand executes a task without the TUI and then exits:
eonyx run "describe what this repository does"
eonyx run -m deepseek-v4-pro --yolo "fix the failing test"It also works in a pipe. The argument takes priority over stdin, so when piping don’t duplicate the prompt as an argument — otherwise the content from stdin is ignored:
{ echo "explain the error:"; cat error.log; } | eonyx runThe response text is streamed to stdout, while tool activity and token statistics go to stderr, so you can safely redirect the output into a file or a pipe.
Flags:
--model/-m— the model--session/-s <id>— continue a specific session--continue/-c— continue the most recent one--yolo— disable tool confirmations--json— events as NDJSON instead of text--system-prompt— replace the system prompt
Exit codes distinguish outcomes for CI:
0— success2— usage error3— API error4— the task finished, but a tool was blocked by the permission gate5— hit themax_stepslimit130— interrupted with Ctrl+C
1.4 The remaining subcommands
| Command | Purpose |
|---|---|
eonyx | interactive TUI chat |
eonyx run "…" | headless agent run |
eonyx sessions | list of saved sessions |
eonyx info | configuration, data, and project paths |
eonyx config | the final (merged) configuration |
eonyx clean | remove its own configuration files |
1.5 Keys and commands in the TUI
| Key | Action |
|---|---|
Enter | send the message |
Ctrl+J | line break in the input field |
↑ / ↓ | history of your messages |
Esc | interrupt the running turn |
/ | command palette (on empty input) |
@ | file path autocompletion (Tab inserts) |
? | help (on empty input) |
Ctrl+P | command palette |
Ctrl+N | switch model |
Ctrl+S | session manager |
Ctrl+K | skills and MCP servers (on/off) |
Ctrl+O | expand/collapse tool output |
Ctrl+R | expand/collapse the model’s reasoning |
! <cmd> | run a shell command |
Ctrl+C | quit |
Slash commands: /new, /clear, /add [path], /rename <title>, /fork, /export, /yolo, /plan, /timestamps, /model, /sessions [query], /help, /quit.
! is written into the conversation — the model sees what you ran and what changed (the current directory or environment variables, for example).2 Configuration
EONYX reads eonyx.json from three levels and merges them top down — each next level overrides the previous one:
- Global config
- Windows —
%LOCALAPPDATA%\eonyx\eonyx.json - Linux/macOS —
$XDG_CONFIG_HOME/eonyx/eonyx.json(~/.config/…by default)
- Windows —
- Global data
- Windows — the same path
- Linux/macOS —
$XDG_DATA_HOME/eonyx/eonyx.json(~/.local/share/…by default)
- Project config
eonyx.jsonor.eonyx.json— searched for up the tree from the current directory
The directory where the project config is found becomes the project root: a service folder .eonyx (exports, logs) appears inside it. The paths can be overridden with the EONYX_GLOBAL_CONFIG, EONYX_GLOBAL_DATA, and EONYX_CACHE_DIR environment variables. To see what was loaded from where: eonyx info and eonyx config.
2.1 A full eonyx.json example
This is the default config EONYX creates on the first run — it contains every supported top-level key:
{
"providers": {
"deepseek": {
"type": "openai",
"base_url": "https://api.deepseek.com",
"api_key": "$DEEPSEEK_API_KEY"
},
"local": {
"type": "openai",
"base_url": "http://localhost:11434/v1",
"api_key": ""
}
},
"models": [
{"id": "deepseek-v4-flash", "provider": "deepseek", "context_window": 1000000, "input_price": 0.14, "output_price": 0.28},
{"id": "deepseek-v4-pro", "provider": "deepseek", "context_window": 1000000, "input_price": 0.435, "output_price": 0.87},
{"id": "qwen2.5-coder", "provider": "local", "context_window": 32768, "input_price": 0, "output_price": 0}
],
"default_model": "deepseek-v4-flash",
"max_steps": 50,
"permissions": {
"allowed_tools": []
},
"skills": [],
"mcp": [],
"hooks": {},
"report": {
"database_url": ""
},
"system_prompt": "",
"log_file": "",
"retry": {}
}2.2 Providers and models
A provider is a way to reach an API. There is only one type so far — "openai" — and it covers any OpenAI-compatible endpoint:
"providers": {
"openrouter": {
"type": "openai",
"base_url": "https://openrouter.ai/api/v1",
"api_key": "$OPENROUTER_API_KEY"
}
}The api_key and base_url fields can reference environment variables ($OPENAI_API_KEY) — they are expanded after the layers are merged, so secrets are not stored in the file.
A model binds an id to a provider:
| Field | Purpose |
|---|---|
id | the model name as the API understands it |
provider | a key from the providers block |
context_window | context size in tokens — triggers auto-summarization of history |
input_price | price per 1M input tokens (USD), for the cost counter in the header |
output_price | price per 1M output tokens (USD) |
max_steps limits the number of tool-call rounds within a single turn (50 by default).
2.3 Permissions
The safe tools — read, ls, glob, grep, git_status, git_diff, git_log, todo_write — are always allowed. Everything else (writing, editing, bash, git commits, MCP tools…) requires permission:
"permissions": {
"allowed_tools": ["bash", "write", "edit"],
"sandbox": true
}allowed_tools— the list of tools that run without asking.sandbox— locks the file tools (read/write/edit/multi_edit/ls) inside the project root; off by default.--yolo(or/yoloin the TUI) — disables the gate entirely for the duration of the session.
In the TUI an interactive layer works on top of the static policy: for a tool that isn’t in the allowlist, EONYX shows an Allow once / Allow always (this session) / Deny dialog. A denial doesn’t kill the turn — the model receives it as a tool error and adapts.
/plan enables a stricter gate: only read tools are available, the agent explores the code and proposes a plan. Once the plan is ready, EONYX asks you: implement it, allow edits, or keep planning.2.4 Hooks
Hooks are shell commands around tool calls. The format: tool name → before / after:
"hooks": {
"write": {
"before": "echo \"writing: $EONYX_INPUT\" >> .eonyx/audit.log",
"after": "gofmt -l ."
},
"bash": {
"before": "[ \"$EONYX_CWD\" = \"$HOME\" ] && exit 1 || exit 0"
}
}Rules:
beforeruns before the tool; a non-zero exit code blocks the call.afterruns after it; its output is appended to the tool result (the model sees it). Errors inafterdon’t break the result.- Context is passed through environment variables rather than by substitution into the command text — injection via the input content is impossible:
EONYX_TOOL— the tool nameEONYX_PHASE—before/afterEONYX_CWD— the working directoryEONYX_INPUT— the JSON inputEONYX_RESULT— the result, only inafter
- Each hook gets 30 seconds; hooks run in the same shell session as the
bashtool.
2.5 Other keys
| Key | Purpose |
|---|---|
skills | additional skill directories (see the Skills article) |
mcp | the list of MCP servers (see the MCP article) |
report.database_url | PostgreSQL for the read-only reporting tools empty — the tools are not registered |
system_prompt | a full replacement for the generated system prompt |
log_file | a log path instead of the standard one; supports $ENV |
retry | max_retries — 3 by defaultbase_delay_ms — 500, doubles up to 30 sresponse_header_timeout_sec — 60 |
3 Summary
- Installation
make buildfrom source or a binary from GitHub Releases- check:
eonyx --version
- Running
eonyx— interactive TUIeonyx run "task"— headless, stdout/stderr separated
- Configuration
- the
eonyx.jsoncascade: global → data → project - strict schema,
$ENVreferences for secrets
- the
- Models
- any OpenAI-compatible API
context_windowtriggers auto-summarization- prices — the cost counter in the header
- Permissions
- reading is always allowed
- everything else — via
allowed_tools, the TUI dialog,--yolo, or/plan
- Hooks
before/afteraround tools- context through
EONYX_*variables beforecan block