# Aider Admin & Developer Guide

This guide is for the people who deploy, operate, secure, and extend Aider: platform admins standing it up for a team, DevOps engineers wiring it into CI, and developers who need to understand its internals. It documents Aider's architecture, the complete configuration surface, security posture, operational procedures, and a module-by-module developer reference.

For installation and day-to-day usage, see the companion **User Guide**.

> **What Aider is, in one sentence:** a Python command-line application that mediates between a git repository and a large language model — assembling source context (including a tree-sitter "repo map"), prompting the model to produce structured edits, applying and committing those edits, and optionally linting/testing the result.

---

## Table of Contents

1. [Executive Summary](#1-executive-summary)
2. [Architecture Overview](#2-architecture-overview)
3. [Component Inventory](#3-component-inventory)
4. [Requirements](#4-requirements)
5. [Configuration Mastery](#5-configuration-mastery)
6. [Model Subsystem](#6-model-subsystem)
7. [The Edit-Format / Coder System](#7-the-edit-format--coder-system)
8. [The Repo Map](#8-the-repo-map)
9. [Git Subsystem](#9-git-subsystem)
10. [Security](#10-security)
11. [Deployment Patterns](#11-deployment-patterns)
12. [Operations](#12-operations)
13. [Developer Internals](#13-developer-internals)
14. [Testing Strategy](#14-testing-strategy)
15. [Potential Improvements](#15-potential-improvements)
16. [Quick Reference](#16-quick-reference)

---

## 1. Executive Summary

| Attribute | Value |
|-----------|-------|
| Project | Aider — AI pair programming in your terminal |
| Package (PyPI) | `aider-chat` |
| Entry-point command | `aider` (→ `aider.main:main`) |
| Language | Python (requires `>=3.10,<3.15`) |
| License | Apache-2.0 |
| Provider abstraction | [LiteLLM](https://docs.litellm.ai/) (works with virtually any LLM) |
| Persistence | The user's **git repository** (no database/server of its own) |
| Interfaces | Interactive terminal chat, one-shot CLI, IDE watch mode, Streamlit browser GUI, web-chat copy/paste |
| Deployment model | Local developer tool / CLI; no daemon or network service |

Aider is **not** a client/server system. It is a single-process CLI that runs entirely on the developer's machine. Its only outbound network calls are to the configured LLM provider and (optionally) to PyPI for version checks, to product analytics, and to web pages you ask it to scrape. There is no Aider backend to operate.

Operationally, the things an admin cares about are: **(1)** how credentials are supplied and scoped, **(2)** how configuration precedence resolves across machines/teams, **(3)** the model/cost controls, and **(4)** the git safety guarantees. Those are the focus of this guide.

---

## 2. Architecture Overview

```
                         ┌──────────────────────────────────────────────┐
                         │                aider (CLI process)            │
                         │                                               │
  user ──prompt/voice──▶ │  InputOutput (io.py)  ◀── prompt_toolkit      │
                         │       │                                       │
                         │       ▼                                       │
                         │  Commands (commands.py)   /add /web /run ...  │
                         │       │                                       │
                         │       ▼                                       │
   git repo ◀───────────│   Coder  (coders/base_coder.py)               │
   (GitRepo, repo.py)    │     │     ├─ RepoMap (repomap.py) ──tree-sitter│
        ▲                │     │     │      └─ networkx PageRank ranking  │
        │ auto-commit    │     │     ├─ ChatSummary (history.py)         │
        │                │     │     ├─ Linter (linter.py)               │
        │                │     │     └─ edit format (EditBlock/Whole/...) │
   files ◀──apply edits──│     │                                         │
                         │     ▼                                         │
                         │   Model (models.py) ──▶ LiteLLM ──▶ provider  │
                         │                                       (HTTP)  │
                         │                                               │
                         │  Analytics (posthog/mixpanel)  Scraper(/web)  │
                         │  Voice(/voice)  FileWatcher(--watch-files)    │
                         │  GUI(gui.py, Streamlit)  Onboarding(OAuth)    │
                         └──────────────────────────────────────────────┘
```

### Request lifecycle (interactive `code` mode)

1. **Startup** (`main.py:main`) — resolve git root, build the config-file search path, parse args (via `configargparse`, see §5), load `.env` files, register model settings/metadata, select the model, construct `InputOutput`, `Commands`, `GitRepo`, `ChatSummary`, and finally the `Coder` via `Coder.create()`.
2. **Prompt** — `InputOutput.get_input()` collects the user's message (prompt_toolkit provides history, completion, multiline, vi/emacs modes).
3. **Context assembly** — the `Coder` builds the message list: system prompt, repo map (`RepoMap.get_repo_map()`), in-chat file contents, read-only files, chat history (summarized by `ChatSummary` if too large), and the user message.
4. **Model call** — `Model.send_completion()` calls LiteLLM, which dispatches to the provider; the response streams back through `MarkdownStream`.
5. **Edit extraction & application** — the active coder subclass parses the model's reply in its edit format (`get_edits()`) and applies it to disk (`apply_edits()`).
6. **Post-processing** — auto-lint (`Linter`), auto-test (`/test` command), then auto-commit through `GitRepo.commit()` with a weak-model-generated message.
7. **Loop** — control returns to step 2. Mode/model switches raise `SwitchCoder`, which rebuilds the coder while preserving state.

> [!NOTE]
> The whole system is **filesystem- and git-centric**: there is no server-side state. Chat history is a markdown file (`.aider.chat.history.md`), the repo map cache is on disk, and "undo" is just `git revert`-style rollback of Aider's own commits.

---

## 3. Component Inventory

All modules live under the `aider/` package. The most important:

| Module | Class(es) | Responsibility |
|--------|-----------|----------------|
| `main.py` | — | Entry point; arg parsing, environment setup, object wiring, top-level control loop. |
| `args.py` | `get_parser()` | Defines every CLI flag (≈110) via `configargparse`; also the YAML/env config schema. |
| `args_formatter.py` | `YamlHelpFormatter`, `MarkdownHelpFormatter`, `DotEnvFormatter` | Render the sample `.aider.conf.yml` / `.env` / docs from the parser. |
| `coders/base_coder.py` | `Coder` | The core engine: context assembly, model calls, edit application, lint/test/commit orchestration. `Coder.create()` is the factory. |
| `coders/*.py` | 14 coder subclasses | One per edit format (see §7). |
| `commands.py` | `Commands`, `SwitchCoder` | All `/slash` commands (40+ `cmd_*` methods) and tab-completions. |
| `models.py` | `Model`, `ModelSettings`, `ModelInfoManager` | Model registry, aliases, per-model settings/metadata, sanity checks. |
| `repomap.py` | `RepoMap` | Tree-sitter symbol extraction + networkx PageRank ranking → the repo map. |
| `repo.py` | `GitRepo` | All git operations: tracked files, diffs, commit, attribution, ignore handling. |
| `io.py` | `InputOutput`, `AutoCompleter`, `ConfirmGroup` | Terminal I/O via prompt_toolkit; prompts, colors, history, completion. |
| `history.py` | `ChatSummary` | Summarizes chat history when it exceeds the token budget. |
| `linter.py` | `Linter`, `LintResult` | flake8 (Python) + tree-sitter syntax checks; per-language lint commands. |
| `watch.py` | `FileWatcher` | Watches files for `ai`/`ai!`/`ai?` comments (IDE mode). |
| `scrape.py` | `Scraper` | `/web` page fetching (Playwright or httpx) + pandoc → markdown. |
| `voice.py` | `Voice` | Microphone capture (`sounddevice`/`soundfile`) + Whisper transcription. |
| `gui.py` | `GUI`, `CaptureIO` | Streamlit browser interface. |
| `analytics.py` | `Analytics` | Opt-in anonymous usage analytics (PostHog + Mixpanel). |
| `onboarding.py` | `OAuthCallbackHandler` | OpenRouter OAuth and default-model selection for first-time users. |
| `help.py` | `Help` | In-chat `/help` knowledge base over Aider's own docs. |
| `exceptions.py` | `LiteLLMExceptions`, `ExInfo` | Maps LiteLLM exceptions to retry/no-retry behavior. |
| `mdstream.py` | `MarkdownStream` | Live markdown rendering of streamed responses (rich). |
| `copypaste.py` | `ClipboardWatcher` | Auto copy/paste mode plumbing. |
| `deprecated.py` | `handle_deprecated_model_args` | Back-compat for old `--sonnet`/`--4o`/etc. shortcut flags. |
| `versioncheck.py` | — | Update checks, `--upgrade`, `--install-main-branch`. |
| `report.py` | — | Uncaught-exception reporting and `/report` GitHub issue helper. |

---

## 4. Requirements

### Runtime

| Requirement | Detail |
|-------------|--------|
| Python | `>=3.10,<3.15` (3.10–3.14). |
| OS | Linux, macOS, Windows. |
| git | Recommended; required for auto-commit/undo. Index version 1 or 2. |
| Network | Outbound HTTPS to the chosen LLM provider. |

### Key dependencies (from `requirements.txt`)

| Dependency | Pinned (at this commit) | Role |
|------------|-------------------------|------|
| `litellm` | 1.82.3 | Provider-agnostic LLM gateway. |
| `openai` | 2.28.0 | OpenAI SDK (used via litellm). |
| `gitpython` | 3.1.46 | Git operations. |
| `prompt-toolkit` | 3.0.52 | Terminal input UI. |
| `rich` | 14.3.3 | Styled output / markdown rendering. |
| `configargparse` | 1.7.5 | Unified CLI + env + YAML config parsing. |
| `grep-ast` | 0.9.0 | Tree-sitter-backed code structure extraction (repo map). |
| `tree-sitter-language-pack` | 0.13.0 | Grammars for 100+ languages. |
| `networkx` | 3.4.2 | PageRank ranking for the repo map. |
| `scipy` / `numpy` | 1.16+ / 2.3+ | Numerical backing for ranking. |
| `diskcache` | 5.6.3 | On-disk caches (repo-map tags). |
| `pathspec` | 1.0.4 | `.gitignore`/`.aiderignore` matching. |
| `beautifulsoup4`, `pypandoc` | — | Web scraping → markdown. |
| `sounddevice`, `soundfile`, `pydub` | — | Voice capture. |
| `posthog`, `mixpanel` | — | Analytics. |
| `watchfiles` | 1.1.1 | File watching for IDE mode. |
| `pillow` | 12.1.1 | Image handling. |

### Optional extras

| Extra | Adds |
|-------|------|
| `aider-chat[browser]` | `streamlit` for the GUI. |
| `aider-chat[help]` | Embeddings/RAG deps for `/help`. |
| `aider-chat[playwright]` | Headless browser for JS-heavy `/web` pages. |
| `aider-chat[dev]` | Test + lint toolchain. |

---

## 5. Configuration Mastery

### Precedence chain (highest → lowest)

Aider uses `configargparse`, which merges three sources. From `main.py`, the effective precedence is:

```
1. Command-line flags          (e.g. --model sonnet)
2. Environment variables       (incl. those loaded from .env files)
3. .aider.conf.yml             (YAML config file)
4. Built-in defaults
```

Two subtleties from the startup sequence:

- Args are parsed **multiple times**: once to discover the git root and `--env-file`, then `.env` files are loaded (which may define variables referenced by other flags), then args are parsed again so `.env`-provided values take effect.
- Every flag maps to a YAML key (the flag name without `--`) and an environment variable (`AIDER_` + the flag name uppercased with underscores, per `configargparse`'s `auto_env_var_prefix`).

### Config-file search order

`.aider.conf.yml` is searched for in this order (later overrides earlier are reconciled by `configargparse`):

1. Current working directory
2. Git repository root
3. Home directory (`~/.aider.conf.yml`)

Override entirely with `--config <file>` / `-c`.

### `.env` search order

`.env` files are loaded with `override=True` from (first loaded wins precedence as loaded last in list, after reversal):

1. `~/.aider/oauth-keys.env` (always loaded first)
2. Home directory `~/.env`
3. Git root `.env`
4. Current directory `.env`
5. `--env-file <file>`

### Worked example: a team baseline

A team can ship a repo-root `.aider.conf.yml` that everyone inherits, while individuals override per-machine via their home config or CLI flags:

```yaml
# <repo>/.aider.conf.yml  — checked into the project
model: sonnet
weak-model: haiku
auto-lint: true
lint-cmd:
  - "python: flake8 --select=E9,F"
test-cmd: pytest -q
auto-test: false
attribute-co-authored-by: true
```

```bash
# A developer overrides the model for a heavy task, without touching the repo config:
aider --model opus
```

> [!IMPORTANT]
> Secrets do **not** belong in `.aider.conf.yml` (it's often committed). Put API keys in `.env` or the environment. Aider auto-adds `.env` to `.gitignore`.

> [!CAUTION]
> The YAML key for "always confirm yes" is `yes-always:`, **not** `yes:`. Aider detects a stray `yes:` line on startup and refuses to run until you fix it (an old footgun that broke arg parsing).

### Configuration domains

The ~110 flags group into these domains (see §16 for the full list, and the User Guide for usage):

| Domain | Representative keys |
|--------|---------------------|
| Model selection | `model`, `weak-model`, `editor-model`, `edit-format`, `alias`, `reasoning-effort`, `thinking-tokens` |
| Credentials | `api-key`, `openai-api-key`, `anthropic-api-key`, `openai-api-base`, `set-env`, `verify-ssl` |
| Git | `git`, `auto-commits`, `dirty-commits`, `attribute-*`, `commit-prompt`, `subtree-only`, `git-commit-verify` |
| Repo map | `map-tokens`, `map-refresh`, `map-multiplier-no-files` |
| Lint/test | `lint-cmd`, `auto-lint`, `test-cmd`, `auto-test` |
| History/cache | `max-chat-history-tokens`, `cache-prompts`, `cache-keepalive-pings`, `restore-chat-history` |
| UI | `pretty`, `stream`, `dark-mode`, `light-mode`, `*-color`, `code-theme`, `vim`, `multiline`, `fancy-input`, `notifications` |
| Files | `file`, `read`, `aiderignore`, `add-gitignore-files`, `encoding`, `line-endings` |
| Voice | `voice-format`, `voice-language`, `voice-input-device` |
| Analytics | `analytics`, `analytics-disable`, `analytics-posthog-host`, `analytics-posthog-project-api-key`, `analytics-log` |
| Updates | `check-update`, `upgrade`, `install-main-branch`, `just-check-update` |

---

## 6. Model Subsystem

### Model roles

| Role | Flag | Purpose |
|------|------|---------|
| Main | `--model` | Primary reasoning + code generation. Default `gpt-4o`. |
| Weak | `--weak-model` | Commit messages, chat-history summarization. Cheaper. |
| Editor | `--editor-model` | Applies edits proposed by the architect in architect mode. |

`Model.commit_message_models()` returns the weak model (falling back to main) for commit generation — which is why commit messages can appear to "ignore" `--model` (see User Guide troubleshooting). Set `--weak-model` to control this.

### Aliases (`MODEL_ALIASES` in `models.py`)

| Alias | Target | Alias | Target |
|-------|--------|-------|--------|
| `sonnet` | `claude-sonnet-4-6` | `deepseek` | `deepseek/deepseek-chat` |
| `opus` | `claude-opus-4-7` | `r1` | `deepseek/deepseek-reasoner` |
| `haiku` | `claude-haiku-4-5` | `flash` | `gemini/gemini-flash-latest` |
| `4o` | `gpt-4o` | `flash-lite` | `gemini/gemini-2.5-flash-lite` |
| `4` | `gpt-4-0613` | `gemini` | `gemini/gemini-3-pro-preview` |
| `4-turbo` | `gpt-4-1106-preview` | `gemini-2.5-pro` | `gemini/gemini-2.5-pro` |
| `35turbo`/`3` | `gpt-3.5-turbo` | `grok3` | `xai/grok-3-beta` |

Add custom aliases at runtime with `--alias name:model-id` (repeatable).

### Model metadata & settings

Aider needs to know each model's context window, costs, and capabilities:

- **Built-in** — bundled `aider/resources/model-metadata.json` plus LiteLLM's database.
- **`.aider.model.metadata.json`** (`--model-metadata-file`) — context size & cost for models Aider doesn't recognize.
- **`.aider.model.settings.yml`** (`--model-settings-file`) — capability settings (default edit format, whether it accepts `reasoning_effort`/`thinking_tokens`, prompt-cache support, etc.).

`ModelInfoManager` fetches/caches model info (including OpenRouter model info) and honors `--no-verify-ssl`. `Model.sanity_check_models()` warns when a model lacks metadata; suppress with `--no-show-model-warnings`.

### Capability gating

`--check-model-accepts-settings` (default on) makes Aider skip applying `reasoning_effort`/`thinking_tokens` to models that don't declare support, warning instead of erroring. Force the setting with `--no-check-model-accepts-settings`.

> [!NOTE]
> Because Aider delegates transport to LiteLLM, **provider support is whatever LiteLLM supports** — OpenAI, Anthropic, Gemini, Azure, Bedrock (`AWS_PROFILE` honored), DeepSeek, xAI, OpenRouter, GitHub Copilot (`GITHUB_COPILOT_TOKEN`), Ollama / any OpenAI-compatible base URL. Aider does not maintain its own provider integrations.

---

## 7. The Edit-Format / Coder System

Aider's central design idea: ask the model to emit changes in a **structured edit format**, then deterministically parse and apply them. Each format is implemented as a `Coder` subclass selected by `Coder.create(edit_format=...)`.

| `edit_format` | Coder class | Notes |
|---------------|-------------|-------|
| `diff` | `EditBlockCoder` | SEARCH/REPLACE blocks — the default for most strong models. |
| `diff-fenced` | `EditBlockFencedCoder` | SEARCH/REPLACE inside a fence (used by some Gemini models). |
| `whole` | `WholeFileCoder` | Model returns entire files. Robust for weaker models. |
| `udiff` | `UnifiedDiffCoder` | Unified-diff hunks. |
| `udiff-simple` | `UnifiedDiffSimpleCoder` | Simplified unified diff. |
| `patch` | `PatchCoder` | Structured add/update/delete/move patch actions. |
| `editor-diff` | `EditorEditBlockCoder` | Edit-only variant for architect mode. |
| `editor-diff-fenced` | `EditorDiffFencedCoder` | Fenced editor variant. |
| `editor-whole` | `EditorWholeFileCoder` | Whole-file editor variant. |
| `architect` | `ArchitectCoder` | Two-model: plan (main) + apply (editor). |
| `ask` | `AskCoder` | Q&A, no edits. |
| `context` | `ContextCoder` | Surfaces relevant surrounding context. |
| `help` | `HelpCoder` | Answers questions about Aider. |
| `func` | (function-call coders) | Tool/function-calling variants (mostly internal/experimental). |

Each coder pairs with a prompt class (`*Prompts`, e.g. `EditBlockPrompts`) that supplies the system prompt and format instructions. The default format per model comes from the model's settings; override with `--edit-format`.

### Edit-application failure modes

When a model emits a malformed edit, the coder raises a descriptive error and asks the model to retry. Representative errors (from source):

- `EditBlockCoder`: `Unpaired ``` in SEARCH/REPLACE block`, `Expected DIVIDER`, `Expected UPDATED or DIVIDER`.
- `PatchCoder` (`DiffError`): `Empty patch section found.`, `Could not find patch context ...`, `Overlapping or out-of-order chunk detected.`, `File referenced in patch not found ...`.
- `UnknownEditFormat` (`base_coder.py`): raised when an invalid `--edit-format` is supplied.

These are the principal correctness-critical paths; they are heavily unit-tested (see §14).

---

## 8. The Repo Map

`RepoMap` (`repomap.py`) is what lets Aider work on large codebases without loading every file.

1. **Symbol extraction** — for each tracked file, `grep-ast` + `tree-sitter-language-pack` parse the source and extract definitions/references (functions, classes, signatures). Tag-query files live under `aider/queries/` (per-language `.scm` files adapted from upstream tree-sitter grammars).
2. **Ranking** — references form a graph; `networkx` **PageRank** ranks symbols by importance and by relevance to the files currently in the chat (personalization).
3. **Budgeting** — the top-ranked symbols are rendered into a compact map sized to `--map-tokens` (default derived per model via `get_repo_map_tokens()`; `0` disables).
4. **Caching** — parsed tags are cached on disk (`diskcache`) so subsequent runs are fast. `--map-refresh` controls rebuild frequency: `auto` (default), `always`, `files` (refresh when the in-chat file set changes), `manual` (`/map-refresh` only).

> [!TIP]
> When `--cache-prompts` is enabled and `--map-refresh` is `auto`, Aider switches the refresh policy to `files` so the cached prompt prefix stays stable (set in `main.py`). This is a cost optimization worth knowing about.

`--map-multiplier-no-files` (default 2) gives the map a larger budget when no files have been explicitly added, since the map is then the model's primary view of the code.

---

## 9. Git Subsystem

`GitRepo` (`repo.py`) wraps GitPython. Key behaviors:

- **Discovery** — `get_git_root()` searches parent directories; if the cwd is the home directory, Aider warns rather than treating `$HOME` as a repo. With no repo, Aider offers to `git init`.
- **Tracked files** — `get_tracked_files()` is the file universe Aider considers (minus `.aiderignore`).
- **Auto-commit** — after applying edits, `commit()` generates a message (weak model, or `--commit-prompt`) and commits. Disable with `--no-auto-commits`.
- **Dirty commits** — by default Aider commits pre-existing dirty changes before editing (`--no-dirty-commits` to disable).
- **Attribution** — author/committer name rewriting and `Co-authored-by` trailers, plus optional `aider: ` commit-message prefixes (`--attribute-*`). `--attribute-co-authored-by` takes precedence over author/committer attribution unless those are explicitly set.
- **Pre-commit hooks** — bypassed with `--no-verify` unless `--git-commit-verify` is set.
- **Ignore files** — `.aiderignore` (configurable via `--aiderignore`) plus `.gitignore` are honored via `pathspec`.
- **Sanity check** — `sanity_check_repo()` rejects unreadable/corrupt repos and unsupported index versions (1 or 2 only), offering `git update-index --index-version=2`.

> [!IMPORTANT]
> `/undo` only reverts commits Aider itself authored, identified via attribution — it will not touch a developer's own commits. This is the core safety guarantee for unattended runs.

---

## 10. Security

Aider runs with the developer's full local privileges and talks to external model providers. Treat it as you would any developer tool that can execute code and reach the network.

### Credentials

- API keys are read from CLI flags (`--api-key`, `--openai-api-key`, `--anthropic-api-key`), environment variables, or `.env`/`~/.aider/oauth-keys.env`.
- Aider sets provider keys into `os.environ` at startup so LiteLLM can use them.
- `scrub_sensitive_info()` redacts keys from the logged command line.
- **Keep keys out of `.aider.conf.yml`** (commonly committed). Aider auto-adds `.env` and `.aider*` to `.gitignore`.

> [!CAUTION]
> `--api-key provider=KEY` and `--openai-api-key KEY` place secrets in your shell history and process list. Prefer environment variables or `.env` files for anything beyond a quick test.

### Code execution surface

Aider can execute commands on your machine in several ways — each gated by a confirmation prompt unless `--yes-always` is set:

| Vector | Control |
|--------|---------|
| `/run` and `!` shell commands | Interactive confirmation; output optionally fed to the model. |
| `--test-cmd` / `--lint-cmd` | Run automatically when `--auto-test`/`--auto-lint`. **You** define these commands. |
| Suggested shell commands | The model may suggest commands; gated by `--suggest-shell-commands` (default on) and a confirmation. |
| File edits | Applied to disk, then committed; reversible via git. |

> [!WARNING]
> `--yes-always` removes **all** confirmation prompts, including before running shell/test commands. Only use it in trusted, sandboxed automation. Aider's own benchmark harness runs inside Docker precisely because it executes model-generated code unsupervised.

### Network egress

- **LLM provider** — your prompts (system prompt, repo map, in-chat file contents, chat history) are sent to the configured provider. Anything in a file you `/add` is shared with the model.
- **`/web` scraping** — fetches arbitrary URLs you request (Playwright or httpx). `--disable-playwright` prevents installing/using a headless browser.
- **Version check** — contacts PyPI on launch unless `--no-check-update`.
- **Analytics** — opt-in (see below).
- **SSL** — verified by default; `--no-verify-ssl` disables verification and is set into the environment (`SSL_VERIFY`) and litellm's HTTP clients — use only against trusted internal endpoints.

### Analytics & privacy

`Analytics` (`analytics.py`) sends **opt-in, anonymous** usage events to PostHog/Mixpanel. The product explicitly never collects code, chat messages, API keys, or personal info. On first run Aider asks for consent; users can:

- accept/decline at the prompt,
- pass `--analytics` / `--no-analytics` per session,
- `--analytics-disable` to permanently disable,
- redirect to a self-hosted PostHog with `--analytics-posthog-host` / `--analytics-posthog-project-api-key`,
- log events locally with `--analytics-log`.

> [!TIP]
> For enterprise rollouts, set `analytics-disable: true` in a shared `.aider.conf.yml`, or set `--no-verify-ssl` only for explicitly approved internal model proxies (never globally).

### Reported security items

- Private Vulnerability Reporting request: issue [#5217](https://github.com/Aider-AI/aider/issues/5217).
- A user-reported "AI guardrails" safety report: issue [#5201](https://github.com/Aider-AI/aider/issues/5201) — a reminder that model-generated edits and shell commands require human review unless sandboxed.

---

## 11. Deployment Patterns

Aider is a local CLI, so "deployment" means provisioning it consistently across developers or CI.

### Individual developer

`aider-install` (uv-based isolated environment) or `pipx install aider-chat`. Keep keys in `~/.env` or the shell environment; keep team defaults in a repo-root `.aider.conf.yml`.

### Team / shared baseline

- Commit a repo-root `.aider.conf.yml` with model, lint/test commands, and attribution policy (no secrets).
- Distribute a `~/.aider.conf.yml` template for per-user overrides.
- Pin the Aider version in your environment manifest if you need reproducibility (`aider-chat==<version>`).

### CI / automation

```bash
pip install aider-chat
aider --model sonnet \
      --yes-always --no-check-update --no-analytics \
      --message "Apply the changes described in CHANGE.md" \
      --message-file CHANGE.md
```

- Use `--message`/`--message-file` for one-shot, non-interactive runs.
- `--yes-always` to skip prompts; `--no-check-update` to avoid PyPI calls; disable analytics.
- Provide keys via CI secrets → environment variables.
- **Sandbox** the runner — model-generated edits and any `--test-cmd` execute real code.

### Docker (the benchmark harness pattern)

The repo's `benchmark/Dockerfile` shows the recommended isolation approach for running model-generated code unsupervised: a container with the toolchains installed and `aider[dev]` installed editable. Adapt it for any automation that runs Aider without a human in the loop.

### Containerized via published image

`AIDER_DOCKER_IMAGE` is honored for version-check behavior, indicating Aider is commonly run from a container image; mount your repo as a volume and pass keys as environment variables.

---

## 12. Operations

### Updates

| Command | Action |
|---------|--------|
| `aider --upgrade` | Upgrade to the latest PyPI release. |
| `aider --install-main-branch` | Install the latest from the `main` branch. |
| `aider --just-check-update` | Exit-code-only update check (good for scripts). |
| `aider --no-check-update` | Skip the launch-time update check. |

First-run-per-version state is tracked in `~/.aider/installs.json`; release notes are offered on first run of a new version.

### Logs & state on disk

| Path | Contents |
|------|----------|
| `.aider.chat.history.md` | Human-readable transcript (in git root). |
| `.aider.input.history` | Input history. |
| `.aider.llm.history` | Raw LLM request/response log (only if `--llm-history-file` set). |
| `~/.aider/installs.json` | Per-version first-run tracking. |
| `~/.aider/analytics.json` | Analytics opt-in state + anonymous UUID. |
| `~/.aider/oauth-keys.env` | OAuth-obtained keys (e.g. OpenRouter). |
| Repo-map tag cache | `diskcache` directory (auto-managed). |

### Diagnostics

```bash
aider --verbose            # print config search order, loaded .env files, model metadata/settings
aider --settings           # (in-chat /settings) dump effective settings
aider --show-repo-map      # print the repo map and exit
aider --show-prompts       # print the system prompts and exit
aider --exit               # do all startup work then exit (smoke test)
```

`--verbose` is the first stop for "why did it pick that config/model?" questions — it prints the config-file search order with existence flags, the loaded `.env` files, and the full resolved model metadata and settings.

### Cost & throughput controls

- `--weak-model` for cheap commit/summary work.
- `--cache-prompts` + `--cache-keepalive-pings` to reuse prompt prefixes.
- `--map-tokens` to bound repo-map cost; `/drop` unused files.
- `--max-chat-history-tokens` to control when summarization kicks in.

> [!WARNING]
> Streaming + caching together makes cost estimates inaccurate (Aider warns). For precise accounting, disable one.

### Crash reporting

`report_uncaught_exceptions()` installs a handler that, on an uncaught exception, points users to file a GitHub issue with environment details. `/report` does the same on demand.

---

## 13. Developer Internals

### Repository layout

```
aider/
  __main__.py        # `python -m aider` → main()
  main.py            # entry point & orchestration
  args.py            # configargparse parser (the config schema)
  args_formatter.py  # YAML/.env/markdown help renderers
  coders/            # 14 edit-format coders + prompt classes + base_coder
  commands.py        # /slash command registry
  models.py          # Model/ModelSettings/aliases/metadata
  repomap.py         # tree-sitter + networkx repo map
  repo.py            # GitRepo
  io.py              # InputOutput, AutoCompleter
  history.py         # ChatSummary
  linter.py          # Linter
  watch.py           # FileWatcher (IDE mode)
  scrape.py          # /web Scraper
  voice.py           # /voice
  gui.py             # Streamlit GUI
  analytics.py       # opt-in analytics
  onboarding.py      # OpenRouter OAuth + default model
  help.py            # /help knowledge base
  exceptions.py      # LiteLLM exception mapping
  mdstream.py        # streamed markdown rendering
  queries/           # per-language tree-sitter tag queries (.scm)
  resources/         # bundled model-metadata.json, etc.
  website/           # docs site (Jekyll/just-the-docs) + install scripts
benchmark/           # Exercism-based benchmark harness (Docker)
tests/               # unit/integration tests
requirements/        # pinned requirement sets + extras
```

### The `Coder` base class

`coders/base_coder.py:Coder` (≈80 methods) is the heart of the system. Notable responsibilities:

- `create()` / `clone()` — factory dispatch by `edit_format`; `clone()` rebuilds a coder for mode switches.
- `format_messages()` / `format_chat_chunks()` — assemble system prompt, repo map, files, history into `ChatChunks` (which also manages **prompt-cache control headers** via `add_cache_control_headers()`).
- `send_message()` / `run()` — the model-call loop, streaming, retries.
- `get_edits()` / `apply_edits()` — overridden per edit format.
- `auto_commit()`, `lint_edited()`, `run_tests()` — post-edit pipeline.
- `get_repo_map()` — delegates to `RepoMap`.

`SwitchCoder` (an exception in `commands.py`) is the mechanism for changing model/mode/edit-format mid-session: it's raised, caught in `main.py`'s loop, and used to rebuild the coder while carrying over state.

### Adding a new edit format (extension point)

1. Create `coders/myformat_coder.py` with a `MyFormatCoder(Coder)` setting `edit_format = "myformat"` and implementing `get_edits()`/`apply_edits()`.
2. Add a matching `MyFormatPrompts(CoderPrompts)` with the system/format prompt.
3. Register the class in `coders/__init__.py`'s imports and `__all__`.
4. `Coder.create()` will then dispatch `--edit-format myformat` to it.

### Adding a new slash command (extension point)

Add a `cmd_<name>(self, args)` method to `Commands` in `commands.py`. The first-line docstring becomes the help text shown in `/help`. Optionally add `completions_<name>()` for tab-completion. The command is auto-discovered — no registration table to edit.

### Exception handling

`exceptions.py:LiteLLMExceptions` maps each LiteLLM exception type to an `ExInfo(retry, ...)` record so the send loop knows whether to retry (e.g. rate limits) or surface the error. A sanity check asserts every LiteLLM exception is accounted for (`{var} is in litellm but not in aider's exceptions list`), so upgrading LiteLLM may require updating this map.

---

## 14. Testing Strategy

Tests live in `tests/` and use `unittest`/`pytest`.

| Test module | Covers |
|-------------|--------|
| `tests/basic/test_main.py` (`TestMain`, ~80 tests) | End-to-end CLI: arg handling, git discovery, config, env loading. |
| `tests/basic/test_coder.py` (`TestCoder`) | Edit permissions, file mentions, context assembly. |
| `tests/basic/test_commands.py` (`TestCommands`, ~70 tests) | Every `/slash` command. |
| `tests/basic/test_editblock.py`, `test_udiff.py`, `test_wholefile.py`, `test_find_or_blocks.py` | Edit-format parsing/application (the correctness-critical paths). |
| `tests/basic/test_repomap.py` (`TestRepoMapAllLanguages`) | Repo map across 40+ languages. |
| `tests/basic/test_models.py`, `test_model_info_manager.py` | Aliases, metadata, sanity checks. |
| `tests/basic/test_repo.py` (`TestRepo`) | Git operations, commit messages, diffs. |
| `tests/basic/test_sendchat.py`, `test_reasoning.py` | Model send loop, retries, reasoning content handling. |
| `tests/basic/test_onboarding.py` | OpenRouter OAuth and default-model selection. |
| `tests/basic/test_ssl_verification.py`, `test_aws_credentials.py` | Security-relevant config paths. |
| `tests/scrape/`, `tests/browser/`, `tests/help/` | `/web` scraping, GUI import, `/help`. |

Run the suite with the `dev` extra installed:

```bash
pip install -e .[dev]
pytest
```

### Benchmark harness

`benchmark/` contains an **Exercism-based** evaluation that measures how well Aider + a given model can translate natural-language requests into passing code. It runs **inside Docker** (it executes model-generated code) and emits a YAML report (`pass_rate_1`, `pass_rate_2`, `percent_cases_well_formed`, cost, timing). Results feed the public leaderboards. Not for end users.

```bash
./benchmark/benchmark.py a-run-name --model sonnet --edit-format diff --threads 10 \
    --exercises-dir polyglot-benchmark
```

---

## 15. Potential Improvements

Observations from the source, framed for maintainers/operators:

- **`base_coder.py` is very large** (≈80 methods on one class). Extracting the prompt-cache, message-assembly, and post-edit (lint/test/commit) responsibilities into collaborators would improve testability.
- **`commands.py` is a single ~3,100-line module** with 40+ commands. The auto-discovery pattern is clean, but grouping commands into mixins by domain (files/git/models/io) would aid navigation.
- **LiteLLM exception coupling** — the assertion that every LiteLLM exception is mapped means a dependency bump can break startup; consider a softer fallback (treat unknown exceptions as non-retryable + warn) to decouple upgrade cadence.
- **Deprecated edit-format coders** (`editblock_func_coder`, `wholefile_func_coder`) raise `RuntimeError("Deprecated, needs to be refactored ...")` — dead code that could be removed.
- **Config precedence is parsed in several passes** in `main.py` (to resolve git root → `.env` → re-parse). Documenting/centralizing this would reduce the risk of subtle precedence bugs.
- **Windows PATH friction on install** (issue [#3123](https://github.com/Aider-AI/aider/issues/3123)) — the `aider-install` path is the mitigation; surfacing it more prominently for Windows users would cut support load.

---

## 16. Quick Reference

### Files Aider reads/writes

| File | Role |
|------|------|
| `.aider.conf.yml` | Config (YAML). Search: cwd → git root → home. |
| `.env` | Secrets/env. Search includes `~/.aider/oauth-keys.env`. |
| `.aiderignore` | Paths Aider must not read/edit. |
| `.aider.model.settings.yml` | Capabilities for unknown models. |
| `.aider.model.metadata.json` | Context/cost for unknown models. |
| `.aider.input.history`, `.aider.chat.history.md` | Session history. |
| `~/.aider/{installs,analytics}.json`, `oauth-keys.env` | Per-user state. |

### Environment variables of note

| Variable | Effect |
|----------|--------|
| `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `OPENROUTER_API_KEY`, `GEMINI_API_KEY`, `DEEPSEEK_API_KEY` | Provider credentials. |
| `OPENAI_API_BASE` | Custom/proxy/local endpoint. |
| `AWS_PROFILE` | Used for Bedrock models. |
| `GITHUB_COPILOT_TOKEN` | Required for Copilot models. |
| `AIDER_*` | Any flag as an env var (e.g. `AIDER_MODEL`). |
| `AIDER_DOCKER_IMAGE` | Signals containerized run (version-check behavior). |
| `AIDER_CACHE_KEEPALIVE_DELAY` | Cache keepalive timing. |
| `SSL_VERIFY` | Set empty by `--no-verify-ssl`. |
| `EDITOR` / `VISUAL` | External editor for `/editor`. |
| `NO_COLOR` | Disable colored output. |

### One-shot / non-interactive modes

| Flag | Exits after |
|------|-------------|
| `--message` / `-m`, `--message-file` / `-f` | Processing one message. |
| `--lint`, `--test`, `--commit` | The named action. |
| `--apply <file>` | Applying edits from a file. |
| `--show-repo-map`, `--show-prompts`, `--exit` | Printing/setup (debug). |
| `--list-models`, `--just-check-update`, `--version` | Reporting. |

### Edit formats

`diff` · `diff-fenced` · `whole` · `udiff` · `udiff-simple` · `patch` · `editor-diff` · `editor-diff-fenced` · `editor-whole` · `architect` · `ask` · `context` · `help` · `func`

### Chat modes

`code` (default) · `ask` · `architect` · `context` · `help`

---

_Generated June 2026 from Aider-AI/aider at 5dc9490. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
