Skip to content
enowdevPublic

About

An open-source AI coding agent for your terminal: specialist agents that plan, build, review and test, with built-in code search and any model provider. One binary.

Topics

Resources

Stars

69 stars

Watchers

1 watching

Forks

Repository files navigation

enowx

An open-source AI coding agent for your terminal.
Specialist agents that plan, build, review and test each other's work, with built-in code search and any model provider. One binary.

Release Stars License Platforms

Website · Docs · Changelog · Discord

enowx: a team of AI agents in your terminal building a landing page and pricing API

curl -fsSL https://enowx.ai/install.sh | sh     # macOS / Linux
irm https://enowx.ai/install.ps1 | iex          # Windows (PowerShell)

Then run enowx.

Why enowx

Most coding agents are one model editing your files, locked to one vendor. enowx is different:

  • A team, not one model. It splits a task across specialist agents (plan, build, review, test) that message each other and review each other's work before it reports back.
  • Any provider, no lock-in. Bring any OpenAI-compatible endpoint, including local or cheaper models (DeepSeek and others). Give each agent its own model.
  • It finds things. Built-in code search (RAG) over your project, cut along the code's syntax, so a function is never split in half.
  • It is honest. It reports what it changed and how it checked it, and says plainly when something was not tested.
  • One binary. Written in Rust, no runtime to install. Runs on macOS, Linux and Windows, on Intel and ARM.

Early release. It runs and is used daily, but the surface is still moving. Bug reports, ideas and PRs are welcome.

enowx                          # open the terminal interface (default)
enowx auth login deepseek      # store a provider's API key (typed, not echoed)
enowx config set model.default deepseek/deepseek-flash   # pin the model to start on
enowx models list              # the connected providers and their models

Install

Early release. v0.1.0 is the first public build; expect bugs and please report them.

Prebuilt binaries are published on the releases page for macOS, Linux and Windows, on Intel/AMD (x86_64) and ARM (aarch64). The installers are served from enowx.ai and download the binary from those releases. The command is enowx, and it also answers to enx, its earlier name: both run the same binary, so habits and scripts that use enx keep working.

macOS (Apple Silicon and Intel)

curl -fsSL https://enowx.ai/install.sh | sh

The script picks the right build, checks its SHA-256, installs to ~/.local/bin/enowx with enx linked beside it, signs it ad hoc so Gatekeeper lets it run, and adds ~/.local/bin to PATH in your shell's rc file (.zshrc, .bash_profile, fish's config.fish, or .profile). Open a new terminal and run enowx.

Linux (x86_64 and ARM64)

The same script. The Linux builds are static (musl), so they run on any distribution, including Alpine, without extra libraries.

curl -fsSL https://enowx.ai/install.sh | sh

Windows (x64 and ARM64)

In PowerShell:

irm https://enowx.ai/install.ps1 | iex

It installs to %LOCALAPPDATA%\Programs\enowx\enowx.exe, with enx.exe as a copy beside it, and adds that folder to your user PATH; open a new terminal afterwards. The bash tool runs commands with the sh from Git for Windows when it is installed, and with PowerShell otherwise. Windows Terminal renders the interface best.

Options and manual install

Both scripts read ENX_VERSION (a release tag such as v0.1.0; default the latest) and ENX_INSTALL_DIR. ENX_NO_MODIFY_PATH=1 stops install.sh from touching your shell config:

curl -fsSL https://enowx.ai/install.sh | ENX_VERSION=v0.1.0 ENX_INSTALL_DIR=/usr/local/bin sh

To install by hand, download the archive for your platform from the releases page, check it against its .sha256 file, and put enowx (enowx.exe) on your PATH:

Platform Archive
macOS, Apple Silicon enowx-aarch64-apple-darwin.tar.gz
macOS, Intel enowx-x86_64-apple-darwin.tar.gz
Linux, x86_64 enowx-x86_64-unknown-linux-musl.tar.gz
Linux, ARM64 enowx-aarch64-unknown-linux-musl.tar.gz
Windows, x64 enowx-x86_64-pc-windows-msvc.zip
Windows, ARM64 enowx-aarch64-pc-windows-msvc.zip

Updating

enowx update            # install the latest release in place of this one
enowx update --check    # only say whether there is one

The interface also looks for a new release when it starts and says so in the status bar; /update installs it. Settings > Updates turns the check off, or has it install updates by itself ([update] in config.toml, or ENX_NO_UPDATE_CHECK=1).

Updating keeps both names on the new version, whichever one you ran. The install scripts also point an older enowx or enx found elsewhere on your PATH (one cargo install put in ~/.cargo/bin, say) at the new one, so no old version is left to start; a program named enx that is not enowx is left alone. Releases before v0.2.3 updated themselves from archives named enx-<target>; releases still publish those, holding both names, so enx update from v0.2.1 and enowx update from v0.2.2 work too.

Uninstalling

curl -fsSL https://enowx.ai/install.sh | ENOWX_UNINSTALL=1 sh

In PowerShell: $env:ENOWX_UNINSTALL = 1; irm https://enowx.ai/install.ps1 | iex. Both remove enowx and enx (and links an install made elsewhere). Your settings, keys and sessions in ~/.enx are kept; delete that folder yourself to remove them too.

From source

With a Rust toolchain:

cargo install --git https://github.com/enowdev/enowxcli enowx-cli

Or build it yourself (see Build). Check the install with enowx --version.

enowxcli opens on a home screen: the wordmark, enow in pixel letters with the mark (an X of lit cells, its centre in orange) as the X, and the composer under it. Until a provider and a model are set, the line under the composer says which one is missing. Open /provider, choose a provider, then enter only its API key. Built-in providers: enxapi, OpenAI, OpenRouter, Groq, and DeepSeek; "Add a custom provider" takes any OpenAI-compatible endpoint. Any number of providers stay connected side by side, each with its own key.

What is inside

Piece Notes
Agent loop, tools, sessions Streaming model calls, paired tool results, JSONL sessions
Terminal interface Framed layout, thought/tool cards, paged right sidebar, theme picker
Roles Three shipped: Orchestrator, Writer, Researcher
Specialists A roster the orchestrator delegates to, including an authorized-assessment security team

The binary opens the terminal interface, with five selectable palettes.

Roles

Role Tools Purpose
Orchestrator read, write, edit, glob, grep, bash, fetch, todo Owns a task end to end, then verifies it
Writer read, write, edit, glob, grep, todo Documentation and prose. No shell
Researcher read, glob, grep, fetch, todo Read-only investigation

Role filtering runs twice: unavailable tools are never advertised to the model, and a call that arrives anyway is refused before dispatch.

Specialists

The orchestrator hands work to a roster of specialists, grouped in the sidebar:

  • LEAD: orchestrator (the default: answers quick questions, delegates the rest, never edits files) and maestro, an all-rounder with every tool that both builds and delegates, for a job that mixes doing and handing out. Pick it with /agent maestro.
  • BUILD: fe (frontend/interface), motion, canvas (standalone single-file HTML pages and tools), be (backend), db, devops, mobile, systems.
  • SECURITY: security, the lead of an authorized security assessment, and its team.
  • SUPPORT: research, review, test, docs, perf, librarian, general.

The security assessment team

security is the single security role a user selects. It leads an authorized penetration test: it confirms the scope and written authorization first, then delegates recon and each testing area to a specialist, consolidates the findings, and finds the chains an individual surface cannot see. Its thirteen specialists are reachable only through it (a Lead delegation, so an ordinary request never lands one directly):

Agent Tests
sec-recon Maps the target: hosts, services, versions, stack, input surface
sec-osint Passive intelligence, no active touch on the target
sec-webapp Web application against the OWASP categories
sec-api REST/GraphQL/gRPC: authorization, injection, mass assignment, tokens
sec-cloud AWS/Azure/GCP/Kubernetes posture
sec-internal Authorized internal hosts, post-foothold
sec-mobile Android/iOS applications and their backend
sec-intercept Proxy-driven request tampering
sec-reverse Binary and firmware analysis
sec-threat-model Attack surface and trust boundaries
sec-ir Incident triage and response
sec-vibecoder Scores how likely a site was AI/boilerplate generated, and reports the gaps it left
sec-report The write-up

Active testing of a domain requires verifiable authorization, not a claim in the chat. authorize_target checks that a connected Cloudflare account controls the domain's DNS zone, which proves control of the domain, and records the domain, its subdomains and the addresses it resolves to as the scope the team may test. A domain the account does not control is refused. Connect the account with enowx auth login cloudflare: it asks which scope (minimal Zone:Read, medium, or full, all read-only), opens the Cloudflare token page with that template pre-filled, verifies the token you paste reads zones, and saves it. For the longest-lived token leave its validity as no expiry (the default, and longer than any end date). The token is read from auth.json or CLOUDFLARE_API_TOKEN.

Every role tests only authorized targets, reads over writes, proves a finding with a benign payload (never a destructive one), and never prints a real secret. Each confirmed issue is recorded with the report_finding tool, which shapes it the same way every time: severity, location, reproduction, impact and fix. The distinct security audit remains as the security skill family, which reads code rather than testing a running target. This is for assessing systems you are authorized to test, such as your own project before release.

Built-in MCP servers

enowx ships four MCP servers of its own, served by the enowx binary (no Node or Python needed). All four are always listed in /mcp, off by default. Turn one on with Tab; a server with no credentials opens its config form instead, which you also reach with c. Changes take effect in the running session, no restart.

Server Gives agents
coolify Applications, servers, databases, services and projects; deploy, start, stop, restart; logs; deployments; env var names
dokploy Projects with their applications, compose stacks and databases; deploy, redeploy, start, stop; logs; deployments; servers; containers
vps Your VPSes over SSH: run a command, or a read-only status (load, disk, memory, Docker)
rag Code search over the workspace: index, search, status, forget (set up in Settings > RAG, see below)

Fill a server in from the TUI (c on its row), or from the CLI, which an agent can run for you: enowx reloads MCP the moment the credentials land, so you never restart the session.

enowx mcp set coolify --url https://coolify.example.com --token <token>
enowx mcp set dokploy --url https://dokploy.example.com --token <token>
enowx vps add prod --host 203.0.113.5 --user root --key ~/.ssh/id_ed25519
enowx vps add db --host 203.0.113.6 --user root --password <password>
enowx vps add lab                     # an alias from ~/.ssh/config, keys or ssh-agent
enowx mcp list
enowx vps list
enowx vps remove db
enowx mcp clear dokploy        # forget its setup and turn it off

A VPS signs in the way ssh would, trying in turn: the key file you gave it (OpenSSH, PEM or PuTTY .ppk; an encrypted one with its passphrase, asked for or given with --passphrase), the keys in ssh-agent (Pageant or the OpenSSH agent on Windows), the IdentityFiles from ~/.ssh/config or else the default ~/.ssh/id_* keys, the password, and keyboard-interactive answered with that password. --host may be an alias from ~/.ssh/config, whose HostName, User and Port are used; --user defaults to the config's. A server that asks for a one-time code is reported, not answered: use a key there. In the TUI, c on the vps row has the same fields.

URLs, hosts and users are kept in ~/.enx/builtin-mcp.json; tokens and VPS passwords and key passphrases in ~/.enx/auth.json (readable by you alone), never in the transcript. Ask the agent to set one up ("connect my Coolify at … with this token") and it runs enowx mcp set for you, then the server is live without a restart. Secret-looking fields and environment variable values are redacted from what the tools return. A VPS's host key is recorded on the first connection (~/.enx/vps_known_hosts) and a different key later is refused before any password is sent. A server you declared yourself under the same name (for example in ~/.claude/mcp.json) keeps the name.

Other MCP clients can run them too: the command is enowx mcp serve coolify (or dokploy, vps, rag) over stdio.

Code search (rag)

rag indexes the workspace into Postgres with the pgvector extension and lets agents search it by meaning. It has a section of its own in Settings (Ctrl+P, then RAG, or /rag):

Field Choices
Code search (RAG) on or off (off by default)
Database a Postgres with pgvector, local (postgres://localhost/enowx) or cloud (Neon, Supabase, RDS, with ?sslmode=require)
Embedding provider Voyage AI, OpenAI, or Custom: any OpenAI-compatible /embeddings endpoint (Ollama, LM Studio, Jina, Mistral, a gateway)
API key the provider's; optional for a local endpoint
Embedding model picked from the provider's (voyage-code-3, voyage-3.5, text-embedding-3-small, ...), typed for a custom endpoint
Dimension picked from the widths the model offers, typed for a custom endpoint
Reranker rerank-2.5, rerank-2.5-lite or off for Voyage; for a custom endpoint, a model its /rerank serves, or blank for none
Index automatically on (the default): the workspace is indexed when a session starts, a file an agent writes or edits is indexed at once, other changes every half minute, and everything before each search

The same from the CLI, which an agent can run for you:

enowx mcp set rag --dsn postgres://localhost/enowx --token <voyage key>
enowx mcp set rag --provider openai --model text-embedding-3-large --dimension 1024 --token <key>
enowx mcp set rag --provider custom --url http://localhost:11434/v1 --model nomic-embed-text --dimension 768

Files are cut along their syntax (tree-sitter for Rust, TypeScript, JavaScript, Python, Go, JSON and CSS): a function, a type, a class method or a config key is one chunk with the comments above it, small neighbours are merged, and only an item larger than about 4,000 characters is split, along its own body (the methods of a class, the statements of a function). Markdown is cut at its headings, other text at its paragraphs; nothing is cut mid-line. Each chunk records where it sits (in impl Store, in Install > macOS) and what it defines, and a search shows both. Code that only moved keeps its embedding and gets its new line numbers.

Indexing runs at low priority (nice 10 on Linux and macOS, below normal on Windows) and holds its full scan of the workspace while a turn is running; the files the turn edits are still indexed at once.

Chunks go to a table per width (enx_rag_chunks_1024, ...) and record the model that embedded them: after a change of model or width, the next index embeds the project again instead of mixing vectors, and a search only compares vectors of the model in use. A search fuses vector and keyword matches, then reranks them when a reranker is set. Indexing is incremental (only changed chunks are embedded again), honours .gitignore, and never reads .env files, keys or lockfiles. Each checkout is its own project. The rag skill, which tells agents when to index and how to search, reaches them only while the server is on.

Agents working together

Off by default; turn it on in Settings > Team (or /team). Each part can then be turned off on its own:

  • Messages. Agents at work at the same time (parallel delegations, the lead that delegated to them) can message each other with message_agent: ask a question, agree on an interface, or point out a mistake in another agent's part. A message reaches its agent at its next step.
  • Shared board. team_board holds what one run decided (an endpoint's shape, a token's name, a file that moved): agents post to it and read it before work that touches another agent's part.
  • Cross-review. When a delegate's work changed files, a reviewer (the review agent unless you pick another) checks it against the task. Its corrections go back to the delegate, in the same session, and the work is checked again, until it passes or the correction rounds (1 to 5, 2 by default) are spent. The caller's report ends with the outcome: CROSS-REVIEW by review: PASS after 1 correction round(s), or the corrections still open.

The same settings live in config.toml under [agent.comms]: enabled, messages, board, review, review_rounds, reviewer.

Claude Code, Codex and other ACP agents

enowx can run on another coding agent instead of the configured model: Claude Code, Codex, Gemini CLI, Kiro CLI, or any program that speaks the Agent Client Protocol on stdio. The agent runs with your own sign-in and subscription; enowx is its client, the way an editor is, and gives it enowx's prompt for each role, its skills, delegation to enowx's specialists and questions to you, over a local MCP server.

/acp claude     run this session on Claude Code: the lead and every specialist
/acp kiro       the same on Kiro CLI (or codex, gemini, a custom agent's name)
/model          pick one of Claude Code's models (arrows, Enter); its efforts follow
/effort         pick its thinking effort
/acp off        back to enowx's own model (/native does the same)
/acp            list the agents with where each stands, and pick one

/acp <name> gets the agent ready first: it installs the adapter into ~/.enx/acp with npm if it is missing (never globally; Node.js 20 or newer is needed), checks that you are signed in, and starts it. If you are not, it says how: claude then /login, codex login, kiro-cli login, or run gemini once. Names complete as you type: /acp c offers claude and codex.

Kiro CLI speaks ACP itself (kiro-cli acp, version 1.25 or newer), so there is no adapter: enowx finds kiro-cli on your PATH and never installs it. Get it from kiro.dev/downloads and sign in with kiro-cli login; the card shows its version and the account type you signed in with. enowx runs it as its own Kiro agent, enowx, kept in ~/.kiro/agents/enowx.json (never in your project), so Kiro loads only enowx's MCP server and not the ones in your own Kiro config, with their sign-in prompts; a file of that name you wrote yourself is left alone and not used. Kiro offers models but no effort setting. If its default model is not available on your plan, the error says so: pick another with /model (auto, for one).

While an agent runs the session, /model and /effort list what that agent offers, read from it, and the choice is kept per agent. Specialists use the same agent and the same model. The status bar always says which brain is in use: ACP Claude Code · Opus 5.5 · effort high · ask me, or enowx native.

Settings > ACP agents has a card for each agent: whether its adapter is installed and you are signed in (Enter on Status installs it, or checks again and reads its models), its default model and effort, chosen from its list, how its permission prompts are answered, and a button that runs the session on it. A row adds a custom ACP agent: its command, arguments and environment.

Permissions, per agent:

  • ask me (the default): each prompt comes to you as a question. A delegated specialist has no one to ask, so its prompts are refused there.
  • enowx's rules: allowed as enowx's own tools are; with the decision model on, a risky shell command goes through its shell gate.
  • bypass: the agent's own bypass mode, nothing is asked. Only when you choose it, and saving says so.

For mixing agents, /agent, select one, and e puts that agent alone on another engine (or back on enowx's model) while the rest follow /acp.

From a shell, enowx acp status shows what is installed and signed in, and enowx acp install claude (or codex, gemini) installs an adapter.

How it runs: one process per agent stays warm, and each enowx session gets its own agent session, so later turns are fast and the agent remembers the conversation. Claude Code is started with only enowx's MCP server (strictMcpConfig), so slow servers in your own Claude config do not hold back its first answer, and with summarised thinking, which enowx shows as reasoning. Its messages, tool calls, diffs and plan appear as enowx's own; Esc cancels its turn. In config.toml: [acp] active (the agent in use), [acp.engines.<id>] (model, effort, permission), [acp.agents] (per-agent exceptions) and [acp.custom.<name>] (command, args, env).

Decision model

A decision model answers small typed questions (yes or no, one of a set, a level on a scale) with a probability for each answer, in milliseconds. enowx can hand it the small judgements a long prompt or a rule makes now. Off by default; with it off, nothing below runs and enowx behaves exactly as without it. Turn it on in Settings > Decision model (or /decision).

Providers:

  • Clef on Cloudflare Workers AI (@cf/cloudflare/clef-flash, the default, or @cf/cloudflare/clef). Needs your Cloudflare account ID and an API token with Workers AI access (CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN are read when the fields are blank).
  • Jev from TypeSafe (jev-latest). Needs a TypeSafe API key (TYPESAFE_API_KEY is read when none is stored).
  • A custom endpoint that speaks the same API as Jev and Clef: its URL, a model name if it wants one, and a key if it needs one.
  • A model configured in enowx, asked for JSON. Slower and less calibrated than a model built for this, but needs nothing new: give it a provider/model, or leave it blank for the one in use, and raise the timeout to a few seconds.

Keys go to ~/.enx/auth.json and are never shown. Test the connection saves the section and asks the provider one question.

What it decides, each use on its own switch with its own threshold (how sure the model must be before its answer is acted on):

  • Brainstorm or build (0.8). For a new message to the lead: whether you asked to brainstorm. Sure either way, the lead is told for that message; unsure, or a large product whose purpose cannot be read, it decides as before.
  • Which specialist (0.7). For the same message: which one specialist the work is for, and whether it needs a security review. Sure, the lead is told to delegate to it directly.
  • When to ask the user (0.8). Before a question reaches you: whether it is yours to answer (taste nothing hints at, money, something that cannot be undone, credentials). Sure it is not, the agent is told to decide and state its assumption; unsure, the question is asked once a turn.
  • Keep tool results whole or cut (0.85). A long tool result that the model is sure is not needed in detail is carried into later turns as its opening lines or its two ends, saying what was left out. Errors and short results are always kept whole, and so is anything the model calls essential.
  • Risky shell commands (0.9). Before a bash command: what is the worst it does. Only a sure "only reads" or "only changes files in the project" runs as before; anything destructive, networked or touching production, and anything the model is unsure of, asks you first. A sub-agent, which cannot ask, does not run it and reports it instead.

Every judgement has a hard timeout (300 ms by default). A late or failed answer takes the path enowx takes without a decision model, and never holds up the turn. Shadow mode decides and records but changes nothing, for comparing the model's decisions with what happens before trusting it.

Every decision is written to ~/.enx/decisions.jsonl: the use, the provider and model, the answers and their probabilities, how long it took, and what was done (applied, shadow, unsure, timeout, error, or what you did when asked). The Log tab lists them under decisions, and enowx decisions [N] prints the last N.

The settings live in config.toml under [decision]: enabled, provider, model, account_id, base_url, timeout_ms, shadow, and [decision.uses.<use>] with enabled and threshold for intent, routing, ask, tool_results and shell.

Terminal commands

/help /new /resume /agent /model /effort /provider /attach /theme /decision /acp /native /skills /mcp /compact /handoff /sidebar /reasoning /tools /preview /rag /team /update /status /clear /stop /retry /commands /quit

/handoff carries the conversation on in a fresh session: its history is folded into a summary, the last few turns are kept as they were, and the same agent holds it, so the context is light again. It asks first whether to keep the old session's history (it stays in /resume) or delete it, with its delegations' transcripts and the size it takes on disk.

The SESSION card in the sidebar shows what the session costs the machine, read every two seconds: the memory of enowx and the processes it started (MCP servers, language servers, the preview browser), their CPU, and the history on disk with its delegations.

A sub-agent at work can be stopped with a right-click on it in the sidebar's Agents tab. The agent that delegated it is told it was stopped, with what it had changed, and can read its whole transcript with delegation_log before it briefs the next one.

/agent lists the roster with the model each agent runs on under it (its own, or the shared default marked · default). Enter switches to the selected agent, m gives it a model of its own from the model list (saved as agent.models.<agent>), and d puts it back on the default model.

/effort chooses how hard the model thinks, from the levels models.dev lists for it (/effort high picks one directly). The level shows beside the model, under the composer and in the status bar, or effort default while the model runs on its provider's default.

The transcript hangs each step's tool calls on a ├─ / └─ rail under the request. Calls that only look around (read, grep, glob, fetch, skill reads) fold into one explored row, and skill bindings into one bound row; click a row to open it. While a turn runs, a line under the composer shows the mark's middle row turning, what the turn is doing, and how long it has taken.

When the provider is down (502, 503, 429, a dropped connection), each call is retried for about three and a half minutes. A reply the provider breaks off mid-stream, or a stream that comes back empty, is asked for again up to three times; one that still breaks tells the agent to send less at once (one file per step, long files in parts), and the turn carries on. A turn that still fails continues from where it stopped by itself, up to three times a minute apart; /retry continues at once and Esc cancels the wait.

Two tabs sit at the top right: Chat and Settings. Settings takes the main column in place of the chat, with its sections listed on the left (Models, General, Models, Providers, Agents, ACP agents, Team, MCP, RAG, Skills, Decision model, Sessions, Display, Theme, Updates) and the chosen one beside them. Ctrl+P switches between Chat and Settings. Settings opens with the section list focused: Up/Down pick a section, shown beside the list, and Enter goes into it. Esc steps back one level: from a form to its list, from a section to the section list, and from the section list to the chat (Left also steps out of a section). With the mouse, a click on a section picks it and a click inside it goes in. /commands opens a searchable list of every command, and typing / lists them above the composer.

Keys work the same on Linux, macOS and Windows. Where a terminal or the OS takes a shortcut for itself, a second form does the same thing:

Key Does
Enter Send (queues while a turn runs)
Shift+Enter, Alt+Enter Newline (Ctrl+J too, when idle)
Ctrl+Enter, Ctrl+S Send now, while a turn runs
Ctrl+Backspace, Alt+Backspace Erase a word
Esc Back one level in Settings, stop a turn, or clear the composer
Ctrl+C Stop a turn, clear the composer, or ask to quit
Ctrl+D Quit, from an empty composer
Ctrl+P Switch between Chat and Settings
Ctrl+R / Ctrl+O Show reasoning / tool output
Ctrl+T Next sidebar tab (Alt+1 to Alt+4 pick one)
Alt+Left/Alt+Right, Alt+B/Alt+F Sidebar pages
Ctrl+G / Ctrl+X Log filter / log detail
Ctrl+B Show or hide the sidebar
Ctrl+Up, Alt+Up Edit, resend or copy your last message
Ctrl+V, Alt+V Attach an image from the clipboard
PgUp / PgDn Scroll the chat

Ctrl+Enter and Shift+Enter are told apart from Enter only by terminals that speak the kitty keyboard protocol (kitty, WezTerm, foot, Ghostty, Alacritty, iTerm2) and by Windows Terminal; enowx turns it on where it is offered. Elsewhere (Terminal.app, GNOME Terminal, tmux) use Ctrl+S and Alt+Enter. AltGr characters type normally on Windows, and a multi-line paste there arrives as one paste. Shortcuts are Ctrl and Alt combinations rather than function keys, which not every terminal passes through.

While a turn runs you can keep typing: Enter puts the message in a queue shown above the composer, and queued messages go one at a time as each turn ends. Ctrl+S (or Ctrl+Enter, or the [send now] button) stops the turn and sends at once: what is typed, or else the first queued message. ↑ in an empty composer takes the last queued message back to edit or delete. Stopping a turn with Esc or Ctrl+C pauses the queue until you send again.

Ctrl+B shows or hides the sidebar; on narrow terminals it opens over the transcript while leaving the composer accessible.

Themes are changed only through /theme: arrow keys preview, Enter saves, Esc cancels. Palettes: Obsidian Ice, Neo Acid, Chrome Void, OLED Stealth, and Classic Amber. NO_COLOR is respected; unset it to see palette colours.

Mouse: drag over the transcript copies text to the clipboard on release, click on a rendered file path opens it with the OS default application, and the scroll wheel scrolls whatever is under the pointer a row a step: the transcript, the side card, or an open window's list, whose selection the wheel leaves where it is (the keys move it).

/provider lists every provider with whether it is connected and whether the model in use is on it. Enter on a built-in provider asks for its key; a custom one opens its name, base URL, key and model-list URL. d removes a provider's stored key, and a second d removes a custom provider.

/model lists the models of every connected provider in one place, the favourites and recent picks first. Type to search, Enter to use a model, Ctrl+F to mark a favourite, Ctrl+N to add a model by hand, Ctrl+E to edit a model's context window, thinking effort, vision and prices, Ctrl+R to ask the providers for their lists again. A model is always named with its provider, deepseek/deepseek-flash, and a pick is remembered in ~/.enx/model.json rather than written to config.toml. /model <provider/model> does the same from the composer.

Configuration

Three files under ~/.enx (or ENX_HOME), each with one job:

File Holds
config.toml Custom providers, a pinned start model, and every other setting. No keys
auth.json One API key per provider, readable by the user alone. enowx auth login/logout edits it
Cloudflare token In auth.json under cloudflare (or CLOUDFLARE_API_TOKEN); proves domain control for a security assessment
model.json The recent and favourite models picked in /model

At start the model in use is the first that can run of: ENX_MODEL, a pinned model.default, then the recent picks. A provider's key also comes from its own environment variable (DEEPSEEK_API_KEY, OPENAI_API_KEY, OPENROUTER_API_KEY, GROQ_API_KEY). ENX_BASE_URL, ENX_API_KEY and ENX_MODEL describe an endpoint for one process, for a container, and are never written. A configuration from before this layout is moved on first load, with the old file kept as config.toml.before-providers.bak.

Key Meaning
model.default Model to start on, as provider/model; empty uses the latest pick
model.active Read only: the model in use
provider.<id>.base_url A custom provider's OpenAI-compatible endpoint
provider.<id>.models_url Where its model list is read
provider.<id>.name Its name in the interface
provider.<id>.models.<model>.context_window A window for one model, over what the provider or catalogue says
agent.models.<agent> A model of its own for one agent, on any connected provider (or m on the agent in /agent)
agent.max_steps Hard cap on model calls per turn
agent.workspace Directory the file and shell tools are rooted in
agent.shell_timeout_secs Kill a shell command after this long
agent.lsp Check written files with the project's language servers (default on)
agent.preview Let agents look at pages in headless Chrome (default on; /preview toggles it)
agent.background_delegation The orchestrator's delegations run on after its turn and their reports wake it (default on)
agent.auto_compact_at Fraction of the context window that triggers auto-compact
agent.compact_keep_last Turns kept verbatim during compact
ui.theme obsidian_ice, neo_acid, chrome_void, oled_stealth, or classic
ui.currency Display currency for cost readouts (USD, IDR, JPY, …)
ui.currency_rate Multiplier applied to USD prices for the display currency

Sessions are stored as JSONL under ~/.enx/sessions, one file per session, including tool calls and results for replay. Interrupted calls without a recorded result are marked unavailable rather than executed again automatically. A session records the workspace it was created in and refuses to resume against a different one.

Skills, MCP servers, and per-project agent instructions are discovered from .agents/, .enx/, .claude/, .cursor/, .gemini/, and the standard ~/.config locations. Skills ship inside enowx for interface work (ui, ui-layout, ui-audit, one ui-page-* per kind of page and one ui-part-* per part), for server work (backend, one backend-* per part such as the API, auth, data, jobs and tests, and one backend-stack-* per stack: Next.js, Node, Python, Go, Rust, Laravel, Java, .NET, Rails, plus caching, real-time, files, search and GraphQL), for motion (motion*), the engineering behind an interface (frontend*: state, data, forms, accessibility, performance, testing, SEO, security, errors), databases (database*), infrastructure (devops*), mobile apps (mobile*), low-level work (systems*), tests (testing*), documentation (docs*), security audits (security*), authorized assessment (pentest*), performance (performance*), reviewing (review*), research (research*), gathering (librarian) and running large tasks (orchestration), plus code, writing, i18n and brainstorm (agreeing a design with the user, only when they ask for it or a large product's purpose cannot be told, then the plan documents they choose: PRD, DESIGN, ARCHITECTURE, ERD, API, PLAN, written by the orchestrator with plan_write), each carried by the agents whose work needs it and read only when the work does. A project or user skill of the same name replaces one. A skill installed in the project or ~/ goes to every agent until the orchestrator binds it, with skill_bind (every binding in one call), to the agents whose work it serves; bindings are kept in ~/.enx/skill-bindings.json, and the Skills tab shows who has each one. /skills and /mcp open their Settings sections to toggle or add entries; /compact folds older turns into a summary; auto-compact fires when the context window nears its cap.

After write, edit and multi_edit, the file goes to its language server (rust-analyzer with clippy, typescript-language-server, pyright and ruff, gopls) and the errors and warnings come back with the result, so an agent fixes a type error before it builds anything on top of it. An edit waits only for the server's first answer; the diagnostics tool waits for the full check. A server that is not installed is named once, with its install command. agent.lsp = false turns this off.

Every change an agent makes goes through three checks before it lands:

  • Rules. Markdown rules (a pattern, the files it applies to, and what to do instead) are checked on the code the change adds. block refuses the change and returns the rule; remind lets it through with the rule attached. enowx ships rules for secrets in code, any, empty catches, index keys, Box::leak, deprecated Go and Python APIs, transition: all and removed focus outlines; add or override them in ~/.enx/rules/ or the project's .enx/rules/ (severity: off turns one off). A line with enowx-allow: <rule> passes a blocking rule.
  • Syntax. Rust, TypeScript, TSX, JavaScript, Python, Go, JSON and CSS files are parsed before and after the change. When a change breaks a file that parsed, a quick model call mends the changed region; when that fails, an edit is refused with the error's line.
  • Language server, as above.

read shows each line with an anchor (12#a3f:text), and edit_lines changes whole lines by those anchors, so an agent never has to repeat the old text exactly, and an edit against a stale read is caught. lsp asks the language server for a definition, references, a symbol's type, a file's symbols, or a rename across every file.

Calls in one step that only look (read, glob, grep, fetch, diagnostics, ui_check, and at most one bash beside them) run at the same time; writes and everything else keep their order. A picture that is already in the conversation is not sent to the model again.

The orchestrator does not wait on its specialists: a wave it delegates runs in the background, its turn ends, and the status bar says how many agents are working. When the whole wave has finished, their reports start its next turn on their own. Tests and review run only when the user chose them at the start.

preview shares one headless Chrome across every look, each in a throwaway browser context, two at a time; the browser closes after 90 seconds without a look and never outlives enowx. Looking again at a page with no file changed returns the last result instead of opening a browser.

File tools reject paths and symlinks outside the workspace. bash runs with the user's OS permissions and is not a sandbox; use only with trusted tasks and providers.

Build

cargo build --release
cargo test --workspace

Install the binary (cargo emits it as enowx, per [[bin]] in crates/enowx-cli/Cargo.toml):

which -a enowx                                     # expect no output before installing
install -m 755 target/release/enowx ~/.local/bin/enowx

Releasing

Pushing a v* tag runs .github/workflows/release.yml: it builds enowx for the six platforms above and publishes the archives and their checksums as a GitHub release. Running the workflow by hand builds without publishing.

git tag v0.1.0 && git push origin v0.1.0

Live reload while developing

enowx dev                     # rebuild and relaunch the interface on every source change
enowx dev --session <id>      # pin one conversation across reloads
enowx tui --session <id>      # resume a session directly

Run enowx dev from this checkout. It watches crates/ and Cargo.toml, keeps the interface in the foreground, and on each save rebuilds and relaunches it while resuming the newest session in this workspace.

Licence

Apache License 2.0. See LICENSE and NOTICE.

About

An open-source AI coding agent for your terminal: specialist agents that plan, build, review and test, with built-in code search and any model provider. One binary.

Topics

Resources

Stars

69 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages