aider
Aider is an AI-powered pair programming CLI tool that uses LLMs (GPT-4, Claude, etc.) to edit code directly in your local git repository. It provides multiple code editing strategies (whole-file replacement, search/replace blocks, unified diffs) and manages the full workflow of sending code context to LLMs, applying their suggested edits, and committing changes to git.
Tech Stack
Key Features
- Strategy-based Code Editing
- Git-integrated Workflow
- Repository Map Generation
- Interactive Slash Commands
- Multi-model Benchmarking Suite
- Lint and Auto-fix Loop
- Browser-based GUI
- Documentation-aware Help System
- Privacy-respecting Analytics
- GitHub Issue Management Automation
Entry Points
Start here when working with this codebase
aider/__main__.pyExecutable entry point that bootstraps the aider CLI application via `python -m aider`
Start here when tracing how the application launches, understanding the boot sequence, or adding pre-initialization logic
aider/args.pyDefines ALL command-line arguments, environment variable mappings, and config file options using argparse
Start here when adding a new CLI flag, configuration option, or changing default values
aider/commands.pyHandles all slash commands (/add, /drop, /run, /help, etc.) in the interactive REPL, routing user input to coder, git, and model subsystems
Start here when adding a new slash command or modifying how existing commands behave
aider/gui.pyBrowser-based Streamlit UI that mirrors CLI functionality with visual controls and chat interface
Start here when modifying the web interface or adding UI-only features
benchmark/benchmark.pyRuns AI models against standardized programming exercises, collects metrics, and generates reports
Start here when adding new benchmark exercises, modifying scoring logic, or integrating new model evaluation workflows
aider/__init__.pyDefines and validates the package version string used across the application
Start here when bumping the version or changing version validation logic
aider/analytics.pyManages analytics consent, routes events to providers, and respects privacy preferences
Start here when adding new tracked events, modifying consent flow, or integrating a new analytics provider
aider/help.pyBuilds and queries a vector search index over aider documentation to answer /help questions
Start here when modifying how documentation is indexed or how help queries are answered
How to Make Changes
Common modification patterns for this codebase
Add a new CLI argument or configuration option
aider/args.pyAdd a new argument definition using `group.add_argument(...)` inside the appropriate argument group (e.g., `model_group`, `output_group`, `git_group`). Include `--flag-name`, `type`, `default`, `help`, and optionally `env_var` for environment variable support.
Pattern: Follow the pattern of existing arguments like `--model` or `--auto-commits` in aider/args.py — each uses `group.add_argument` with metavar, default, help text, and const/action for boolean flags
aider/commands.pyIf the new option needs to be changeable at runtime via a slash command, add a handler method `cmd_<name>(self, args)` and register it in the command dispatch logic
Pattern: See how `cmd_model` or `cmd_map_tokens` is implemented in aider/commands.py — each reads from `self.coder` or `self.coder.main_model` and updates state
aider/format_settings.pyIf the argument contains sensitive data (API keys, tokens), add it to the masking logic so it is redacted in logs and settings output
Pattern: See how aider/format_settings.py masks sensitive fields — it checks argument names against known sensitive patterns and replaces values with masked strings
tests/basic/test_args.pyAdd a test that verifies the new argument is parsed correctly with expected defaults and type coercion
Pattern: Follow the test structure in tests/basic/ where each test function creates an argument parser via `get_parser()` and asserts parsed values
Conventions to follow:
Add a new slash command to the interactive REPL
aider/commands.pyAdd a new method named `cmd_<commandname>(self, args)` to the `Commands` class. The method receives the user's arguments as a string. Use `self.io` for output, `self.coder` for accessing the current coder state, and `self.coder.repo` for git operations.
Pattern: See how `cmd_add(self, args)` and `cmd_drop(self, args)` are implemented in aider/commands.py — they parse the args string, validate input, interact with `self.coder.abs_fnames`, and call `self.io.tool_output()` for feedback
aider/commands.pyAdd a docstring to the new `cmd_<commandname>` method. The first line of the docstring becomes the help text shown when users type `/help`.
Pattern: See how `cmd_help` reads docstrings from all `cmd_*` methods to build the help listing in aider/commands.py
aider/commands.pyIf the command needs tab-completion, add a `completions_<commandname>(self)` method that returns a list of completion strings
Pattern: See how `completions_add(self)` returns file paths and `completions_model(self)` returns model names in aider/commands.py
tests/basic/test_commands.pyAdd test cases for the new command, mocking `self.io` and `self.coder` as needed
Pattern: See how tests in tests/basic/test_commands.py create a `Commands` instance with mock IO and coder objects, then call `cmd_*` methods directly and assert outcomes
Conventions to follow:
Add a new coder strategy (edit format)
aider/coders/base_coder.pyUnderstand the base coder class which defines the interface all coder strategies must implement: `get_edits()`, `apply_edits()`, prompt template attributes (`main_system`, `example_messages`, etc.), and the `edit_format` class attribute
Pattern: Read aider/coders/base_coder.py to understand the abstract interface — all coders inherit from `Coder` and override `get_edits()` and `apply_edits()`
aider/coders/editblock_coder.pyUse this as the reference implementation for creating a new coder. Create a new file `aider/coders/<newformat>_coder.py` with a class that inherits from `Coder`, sets `edit_format = '<newformat>'`, and implements `get_edits()` to parse LLM output and `apply_edits()` to modify files
Pattern: See how `EditBlockCoder` in aider/coders/editblock_coder.py defines `edit_format = 'diff'`, sets prompt template paths, implements `get_edits()` to parse SEARCH/REPLACE blocks, and `apply_edits()` to apply them
aider/coders/editblock_prompts.pyCreate a corresponding prompts file `aider/coders/<newformat>_prompts.py` with a class containing `main_system`, `example_messages`, and `files_content_prefix` string attributes that define the LLM prompt templates for the new format
Pattern: See how aider/coders/editblock_prompts.py defines `EditBlockPrompts` with multi-line string attributes for system prompts and example conversations
aider/coders/__init__.pyRegister the new coder by importing it and adding it to the coder registry so it can be selected via CLI arguments
Pattern: See how aider/coders/__init__.py imports `EditBlockCoder`, `WholeFileCoder`, `UnifiedDiffCoder` and makes them available for selection
aider/args.pyAdd the new edit format as a valid choice for the `--edit-format` argument
Pattern: See how `--edit-format` in aider/args.py lists valid format strings that map to coder classes
tests/basic/test_coder.pyAdd tests for the new coder's `get_edits()` parsing and `apply_edits()` file modification logic
Pattern: See how tests/basic/test_coder.py tests coder instantiation, edit parsing, and file application for existing coder types
Conventions to follow:
Add support for a new LLM model or provider
aider/models.pyAdd the new model's metadata to the model registry. Define its name pattern, context window size, default edit format, and any provider-specific settings. If the model needs special handling, add a conditional block.
Pattern: See how aider/models.py defines model entries with attributes like `name`, `edit_format`, `weak_model_name`, `use_repo_map`, `send_undo_reply`, `accepts_images`, and `max_chat_history_tokens` — follow the pattern of existing GPT-4 or Claude model definitions
aider/sendchat.pyIf the new provider requires custom API call handling (non-standard auth, custom headers, streaming differences), modify the `send_completion()` function to handle the provider's specifics
Pattern: See how aider/sendchat.py wraps litellm completion calls with retry logic, streaming handling, and hash-based caching — add provider-specific branches where needed
aider/exceptions.pyIf the new provider returns unique error codes or exception types, add mappings so they produce user-friendly error messages
Pattern: See how aider/exceptions.py maps LiteLLM exception types to human-readable descriptions with retry guidance
aider/args.pyIf the provider needs a dedicated CLI shortcut flag (like `--openai` or `--anthropic`), add it to the model argument group
Pattern: See how `--model` and provider-specific shortcut flags are defined in aider/args.py
tests/basic/test_models.pyAdd tests verifying the new model's metadata is correctly loaded and its edit format, context window, and capabilities are set properly
Pattern: See how tests/basic/test_models.py tests model lookup, attribute resolution, and fallback behavior
Conventions to follow:
Add a new benchmark exercise or modify benchmark scoring
benchmark/benchmark.pyModify the exercise loading, execution, or scoring logic. To add a new exercise set, update the directory scanning and test execution pipeline. To change scoring, modify the result collection and pass/fail determination.
Pattern: See how benchmark/benchmark.py iterates over exercise directories, runs the coder against each, executes test suites, and collects pass/fail results with timing metrics
benchmark/plots.pyUpdate visualization code if the new benchmark data needs new chart types or if scoring changes affect how results are displayed
Pattern: See how benchmark/plots.py uses matplotlib to generate bar charts and comparison plots with model names on axes and percentage scores — add new plot functions following the same `plt.figure()` / `plt.savefig()` pattern
benchmark/problem_stats.pyUpdate the aggregation logic if new metrics or difficulty classifications are needed
Pattern: See how benchmark/problem_stats.py aggregates results across models and languages, computing solve rates and difficulty tiers
benchmark/over_time.pyIf adding a new model to benchmarks, ensure its release date is included so it appears on the timeline visualization
Pattern: See how benchmark/over_time.py maps model names to release dates and plots performance trends chronologically
Conventions to follow:
Add a new analytics event or tracking metric
aider/analytics.pyAdd a new event tracking method or extend an existing one. Define the event name and the properties dictionary to be sent to the analytics provider.
Pattern: See how aider/analytics.py defines event methods that check consent status before calling the provider's `track()` method with an event name string and properties dict
aider/coders/base_coder.pyIf the event should fire during coding operations (e.g., after an edit is applied, after a message is sent), add the analytics call at the appropriate point in the coder lifecycle
Pattern: See how aider/coders/base_coder.py calls analytics methods after key operations like sending messages or applying edits
aider/commands.pyIf the event should fire when a slash command is used, add the analytics call inside the relevant `cmd_*` method
Pattern: See how aider/commands.py integrates with the analytics system by calling tracking methods from command handlers
Conventions to follow:
Add or modify Git integration behavior
aider/repo.pyModify the `GitRepo` class to add new git operations (e.g., new commit strategies, branch handling, diff generation). This is the central abstraction over git operations.
Pattern: See how aider/repo.py wraps gitpython calls in methods like `commit()`, `get_diffs()`, `get_tracked_files()` — each method handles error cases and returns clean Python objects
aider/repomap.pyIf the change affects how the repository map (code structure summary sent to the LLM) is generated, modify the repo map builder here
Pattern: See how aider/repomap.py uses tree-sitter to parse source files, extract symbols, and build a ranked map of the most relevant code structures
aider/commands.pyIf the git feature needs a user-facing command, add a `cmd_*` method that calls the new `GitRepo` method
Pattern: See how `cmd_commit` and `cmd_diff` in aider/commands.py delegate to `self.coder.repo` methods
tests/basic/test_repo.pyAdd tests for the new git operations using temporary git repositories
Pattern: See how tests/basic/test_repo.py creates temp directories with `git init`, makes commits, and tests `GitRepo` methods against real git state
Conventions to follow:
Add or modify web scraping and help documentation features
aider/scrape.pyModify the web scraping logic to handle new content types, change parsing behavior, or add new scraping targets
Pattern: See how aider/scrape.py fetches URLs, extracts text content from HTML, and returns cleaned text suitable for LLM consumption
aider/help.pyModify the documentation indexing or query logic. This file builds a vector search index from markdown docs and retrieves relevant passages for /help queries.
Pattern: See how aider/help.py loads markdown files, chunks them, builds embeddings, and performs similarity search to find relevant documentation passages
aider/commands.pyIf adding a new help-related command or modifying how `/help` or `/web` works, update the corresponding `cmd_*` method
Pattern: See how `cmd_help` and `cmd_web` in aider/commands.py call into aider/help.py and aider/scrape.py respectively
Conventions to follow:
Coding Conventions
Standards and patterns used in this codebase
Coder classes follow an inheritance hierarchy with a base Coder class and specialized subclasses for different edit formats, each paired with corresponding prompt template files
EditBlockCoder extends Coder, with prompts in editblock_prompts.py; WholeFileCoder extends Coder with wholefile_prompts.pyUse __main__.py as a thin entry point that delegates to a main() function, keeping the module executable via python -m
from aider.main import main; main()Arguments are defined using argparse with extensive use of environment variable fallbacks (via env_var in add_argument), grouped into logical argument groups, and support YAML/config file overrides
group.add_argument('--model', env_var='AIDER_MODEL', help='...') with configargparse.YAMLConfigFileParserTests use unittest.TestCase as the base class, with GitTemporaryDirectory context managers for isolated filesystem/git testing environments
with GitTemporaryDirectory() as tmpdir: ... creates a temp dir with git init for test isolationPrompt templates are stored in dedicated *_prompts.py files as class attributes (main_system, example_messages, system_reminder) on a PromptClass, separating prompt content from logic
class EditBlockPrompts: main_system = '''...'''; example_messages = [...]Use broad try/except blocks with informative error messages via self.io.tool_error() or self.io.tool_warning(), avoiding silent failures and providing user-actionable feedback
try: ... except Exception as e: self.io.tool_error(f'Error processing {fname}: {e}')Module-level constants use UPPER_SNAKE_CASE, classes use PascalCase, methods/functions use snake_case, and private/internal methods are prefixed with underscore
DEFAULT_MODEL_NAME = 'gpt-4'; class EditBlockCoder; def get_edits(self); def _parse_response(self)Heavy or optional dependencies are imported lazily inside functions rather than at module top level, to reduce startup time and handle missing packages gracefully
def function(): import numpy as np; import matplotlib.pyplot as plt (inside function body)All user-facing input/output goes through an InputOutput (io) abstraction layer rather than direct print/input calls, enabling testability and consistent formatting
self.io.tool_output('message'); self.io.tool_error('error'); self.io.confirm_ask('proceed?')Package version is defined as a string constant in __init__.py and validated at import time to ensure it's not accidentally corrupted
__version__ = '0.50.0'; assert re.match(r'^\d+\.\d+\.\d+', __version__)Benchmark plotting scripts follow a consistent pattern: load YAML data, process into dataframes or dicts, generate matplotlib figures, and save to specific output paths
Load YAML results → filter/transform → plt.figure() → plt.barh() → plt.savefig('output.png')Git operations use the gitpython library wrapped in helper methods, with automatic dirty-state detection, commit message generation, and safe rollback capabilities
self.repo.git.add(fname); self.repo.git.commit('-m', message); repo.is_dirty()