aerin-agent
v0.0.114
Published
Aerin your open-source coding agent
Maintainers
Readme
Read the code
Aerin's differentiator isn't a feature — it's that you can understand the whole thing. The architecture tour walks the codebase in 8 stops (~20 minutes): the event-stream contract, the agent loop, the permission gate, shadow-git undo, the context economy, sub-agents, and how it all assembles. Every feature's docs page names its source files and invariants. The src/ tree stays under 10,000 lines, CI-enforced — smallness is a promise, not an accident. If you've ever wanted to know how coding agents actually work, this is the codebase to read — and to contribute to.
$0 to start, too: keyless web search, local models via Ollama/LM Studio/vLLM, and aerin never auto-selects a paid model on your behalf.
Install
npm install -g aerin-agent # or: npx aerin-agentThe installed command is aerin. Requires Node 20+.
Quick start
export ANTHROPIC_API_KEY=sk-ant-... # or OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, OPENROUTER_API_KEY
cd your-project
aerin # interactive TUI
aerin "fix the failing test" # TUI with an opening prompt
aerin --no-tui # plain readline REPL
aerin -p --yolo "summarize this repo" # headless, auto-approve, print, exitSwitch models any time with -m provider/model-id or /model inside the session:
aerin -m openai/gpt-4o
aerin -m google/gemini-flash-latest
aerin -m ollama/llama3.1 # local, no key neededFeatures
Every feature has a page in the docs knowledge base with mechanics, invariants, and source pointers.
- Any model, any provider — Anthropic, OpenAI, Google, OpenRouter, xAI, local Ollama, plus any OpenAI-compatible endpoint via a two-line config entry. The system prompt is tuned per model family and follows
/modelswitches; aerin never auto-selects a paid model. - Real coding tools — read/write/edit (CRLF-safe), glob, ripgrep-accelerated grep, a shell with a proper Windows strategy, background jobs, keyless web search/fetch.
- Sub-agents — read-only researchers with their own context windows, write-capable workers under your permission rules, and named custom agents from markdown files.
- Autonomous goal loop —
/goal <text>keeps working until an evidence-based judge sees it done: fail-open, turn-budgeted, steered by not-done verdicts. - Permissions — read/write/execute tiers, allow rules as prefix globs, deny rules that beat everything (even
--yolo), and a doom-loop breaker that interrupts identical-call retry spirals. - Undo & redo —
/undoreverts the last turn's file changes including bash side effects via a shadow git repo;/redowalks forward. - Hooks — shell hooks around tool calls with a JSON protocol (allow/deny/ask, input rewrite, context injection) plus lifecycle events:
session:start,prompt:submit,turn:end(a stop-gate that can demand more work),compact:pre,session:end. - Provider failover — rate limits, outages, and spent quotas roll onto the next
fallbackModelsentry mid-turn instead of killing it. - Post-edit diagnostics — your typecheck runs after every edit and failures feed straight back; zero-config with a
typecheckscript. - Bounded memory — durable facts in
AGENTS.mdunder a hard 2,500-char budget; a full memory forces consolidation instead of growing forever. - Sessions & recall — JSONL history with
--continue//resume, compaction that updates a structured running summary, and asession_searchtool over past conversations. - Spill files — truncated tool output is saved in full for grepping/slicing instead of re-running commands.
- MCP — paste your
mcpServersconfig and the tools appear; deferred loading keeps big servers from flooding the context. - Skills & custom commands — instruction packs and
/nameprompt templates, Claude Code-compatible (.claude/layouts are read too). - Terminal UI — full-screen Ink TUI with streamed markdown, in-app scrolling, multi-line input,
@filefuzzy autocomplete,/command suggestions, live todo checklist, diff previews, and a context/cost meter — plus--no-tui(REPL) and-p(headless). Plan mode (/plan) makes everything read-only until you approve.
Configuration
Global: ~/.config/aerin/config.json (platform-appropriate). Per-project: .aerin/settings.json. Full reference: docs/configuration.md.
{
"model": "anthropic/claude-opus-4-8",
"subagentModel": "anthropic/claude-haiku-4-5",
"fallbackModels": ["openrouter/deepseek/deepseek-chat"],
"providers": {
"openrouter": { "apiKey": "sk-or-..." },
"deepseek": { "baseURL": "https://api.deepseek.com/v1", "apiKey": "sk-..." },
"ollama": { "baseURL": "http://localhost:11434/v1" }
},
"mcpServers": {
"github": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"] }
},
"permissions": {
"allow": ["bash(git *)", "write(src/*)", "mcp__github__*"],
"deny": ["bash(rm *)", "write(.env*)", "edit(.env*)"]
}
}Any provider name that isn't built in but has a baseURL is served through the OpenAI-compatible adapter — one mechanism covers DeepSeek, Kimi, Groq, Cerebras, Together, Fireworks, LM Studio, vLLM, and friends.
Never put API keys in the project config — it gets committed. Use env vars, the global config, or /connect inside aerin.
Permission rules
Reads are always allowed; writes and commands ask. Rules are simple prefix globs — bash(git *), write(src/*), mcp__github__* — persisted per project when you choose "always". A deny list beats everything, applies to read-tier too, and matches each segment of chained bash commands. Details: docs/permissions.md.
Development
bun install
bun test # unit tests
bun run typecheck
bun run dev # run from source
bun run build # dist/ via tsdownThe core (src/core, src/tools, …) never imports Ink/React — the TUI is one of three frontends over the same AsyncIterable<AgentEvent> stream, which keeps everything testable headless. Agent contributors: start at AGENTS.md and docs/index.md.
License
MIT
