This guide is the deep reference for operators, integrators, and developers working with gpt-engineer — the open-source CLI that generates and improves codebases with large language models. It covers the architecture, the core library API, configuration, deployment (including Docker), security considerations, operations, and the internal pipeline in enough detail to extend or embed the tool.
It is written against gpt-engineer 0.3.1 (commit a90fcd5). For installation and day-to-day usage, see the companion User Guide.
1. Executive Summary
gpt-engineer is a Python application with two distinct layers:
- A reusable core library (
gpt_engineer/core/) that defines a small set of abstractions — an agent, a memory, and an execution environment — plus a LangChain-based LLM wrapper, a robust git-diff engine, and token accounting. The core is provider-agnostic and has no CLI dependencies. - A CLI application (
gpt_engineer/applications/cli/) built on Typer that wires the core into an interactive terminal experience: argument parsing, interactive file selection, human-review feedback, and optional telemetry.
The defining behavior of gpt-engineer is that it not only writes code but can execute it: every generation produces a run.sh entrypoint, and the tool offers to run it. The improve workflow uses a custom unified-diff format with validation and self-correction so that LLM-produced patches apply cleanly to real files.
| Attribute | Value |
|---|---|
| Language | Python (>=3.10,<3.13) |
| CLI framework | Typer |
| LLM integration | LangChain (langchain, langchain-openai, langchain-anthropic, langchain-community) |
| Packaging | Poetry (pyproject.toml) |
| License | MIT |
| Console scripts | gpt-engineer, ge, gpte, bench, gpte_test_application |
| Persistent state | File-based (.gpteng/ per project) — no database |
| Source size | 170 files / ~245 KB of source at the documented commit |
2. Architecture
2.1 Layered view
┌──────────────────────────────────────────────────────────────┐
│ CLI application layer — gpt_engineer/applications/cli/ │
│ │
│ main.py Typer app: parses flags, wires the agent │
│ cli_agent.py CliAgent: orchestrates gen + improve │
│ file_selector.py Interactive TOML-based file picker │
│ learning.py Human-review capture + consent │
│ collect.py RudderStack telemetry (opt-in) │
└───────────────┬──────────────────────────────────────────────┘
│ depends on
┌───────────────▼──────────────────────────────────────────────┐
│ Core library — gpt_engineer/core/ │
│ │
│ ai.py AI: LangChain chat-model wrapper │
│ base_agent.py ┐ │
│ base_memory.py │ abstract interfaces │
│ base_execution_env.py│ │
│ version_manager.py ┘ │
│ prompt.py Prompt value object (text + images) │
│ files_dict.py FilesDict: {path -> content} container │
│ chat_to_files.py Parse LLM output into files / diffs │
│ diff.py Hunk/Diff model + validate & correct │
│ token_usage.py Tokenizer + TokenUsageLog (cost) │
│ project_config.py gpt-engineer.toml reader/writer │
│ linting.py black formatting │
│ git.py git helpers (stage/init/ignore) │
│ preprompts_holder.py loads preprompts/ templates │
│ │
│ core/default/ Concrete implementations: │
│ simple_agent.py SimpleAgent (library-friendly agent) │
│ disk_memory.py DiskMemory (files = key/value store) │
│ disk_execution_env.py DiskExecutionEnv (subprocess runner) │
│ file_store.py FileStore (writes generated files) │
│ steps.py gen_code / gen_entrypoint / improve_fn │
│ paths.py / constants.py path + tuning constants │
└───────────────┬──────────────────────────────────────────────┘
│ uses
┌───────────────▼──────────────────────────────────────────────┐
│ preprompts/ The system prompts that define the AI's role │
│ tools/ custom_steps.py (clarify / lite / self-heal), │
│ supported_languages.py │
│ benchmark/ `bench` CLI for evaluating agents (APPS, MBPP) │
└────────────────────────────────────────────────────────────────┘
2.2 The three core abstractions
gpt-engineer's extensibility rests on three abstract base classes in gpt_engineer/core/. Any alternative implementation can be substituted without touching the rest of the system.
| Interface | File | Contract | Default implementation |
|---|---|---|---|
BaseAgent |
base_agent.py |
init(prompt) -> FilesDict; improve(files_dict, prompt) -> FilesDict |
CliAgent, SimpleAgent |
BaseMemory |
base_memory.py |
A MutableMapping[str | Path, str] — keys are filenames, values are contents |
DiskMemory |
BaseExecutionEnv |
base_execution_env.py |
run, popen, upload(FilesDict), download() -> FilesDict |
DiskExecutionEnv |
BaseVersionManager |
version_manager.py |
snapshot(files_dict) -> str |
(interface only) |
Note
Because the agent is parameterized by functions for code generation, improvement, and execution (
code_gen_fn,improve_fn,process_code_fn), the CLI can swap behaviors at runtime — for example substitutingclarified_gen/lite_genforgen_code, orself_healforexecute_entrypoint— without subclassing.
2.3 Component inventory
| Component | Responsibility |
|---|---|
AI (core/ai.py) |
Wraps a LangChain BaseChatModel. Selects OpenAI / Azure OpenAI / Anthropic based on model name and Azure endpoint. Handles message collapsing, serialization, streaming, vision detection, and rate-limit backoff. |
ClipboardAI (core/ai.py) |
An AI subclass that exchanges messages via the system clipboard instead of an API call. |
Prompt (core/prompt.py) |
Immutable value object holding prompt text, optional image URLs, and an optional entrypoint prompt. Serializes to LangChain content blocks. |
FilesDict (core/files_dict.py) |
A dict subclass mapping filename → content, with type enforcement and to_chat() / to_log() renderers. |
chat_to_files.py |
Parses LLM chat output into a FilesDict (fenced-code regex) and parses/apply unified diffs. |
diff.py |
Hunk and Diff classes; validates LLM-produced diffs against the original file and self-corrects mismatches. |
TokenUsageLog (core/token_usage.py) |
Per-step token counting via tiktoken, plus USD cost estimation for OpenAI models and image-token math for vision. |
Config (core/project_config.py) |
Reads/writes the optional gpt-engineer.toml project file. |
DiskMemory (core/default/disk_memory.py) |
File-backed key/value store; also archives prior run logs. |
DiskExecutionEnv (core/default/disk_execution_env.py) |
Runs the entrypoint as a subprocess and captures output. |
FileStore (core/default/file_store.py) |
Writes a FilesDict to the working directory; runs linting. |
steps.py |
The generation/improvement pipeline functions (see Section 7). |
custom_steps.py (tools/) |
Alternative pipeline functions: clarified_gen, lite_gen, self_heal. |
preprompts/ |
Eight extensionless template files that compose the system prompts. |
3. Requirements & Dependencies
3.1 Runtime requirements
| Item | Requirement |
|---|---|
| Python | >=3.10,<3.13 (CI/docs build on 3.11) |
git |
Optional but recommended; enables file staging and gitignore filtering |
| Network | Outbound HTTPS to the chosen LLM provider (unless using a local model or clipboard mode) |
| Provider key | OPENAI_API_KEY and/or ANTHROPIC_API_KEY |
3.2 Key Python dependencies
Declared in pyproject.toml under [tool.poetry.dependencies]. The most architecturally significant:
| Dependency | Constraint | Role in gpt-engineer |
|---|---|---|
openai |
^1.0 |
Underlying OpenAI client; openai.RateLimitError drives backoff |
langchain |
>=0.1.2 |
Chat-model abstraction, message schema, LLM cache |
langchain_openai |
* |
ChatOpenAI, AzureChatOpenAI |
langchain-anthropic |
^0.1.1 |
ChatAnthropic for Claude models |
langchain-community |
^0.2.0 |
SQLiteCache, OpenAI cost tables |
typer |
>=0.3.2 |
CLI framework for main.py and benchmark/__main__.py |
tiktoken |
>=0.0.4 |
Token counting |
tomlkit / toml |
^0.12.4 / >=0.10.2 |
gpt-engineer.toml and file_selection.toml |
regex |
^2023.12.25 |
Timeout-capable diff parsing |
black |
23.3.0 |
Linting/formatting of selected Python files |
pyperclip |
^1.8.2 |
Clipboard mode |
pillow |
^10.2.0 |
Image sizing for vision token math |
rudder-sdk-python |
>=2.0.2 |
Opt-in telemetry |
datasets |
^2.17.1 |
Benchmark dataset loading |
Dev and docs dependency groups (pytest, mypy, ruff, pre-commit, tox; and the Sphinx stack) are declared under [tool.poetry.group.dev.dependencies] and [tool.poetry.group.docs.dependencies].
Important
The dependency
langchain_openai = "*"is unpinned. When reproducing a build for production, pin it (and ideally the rest of the LangChain stack) to known-good versions — LangChain's minor releases have historically moved import paths.token_usage.pyalready guards one such move with atry/except ImportErroraroundget_openai_token_cost_for_model.
4. Configuration Reference
gpt-engineer has three configuration surfaces: environment variables, the optional gpt-engineer.toml project file, and the per-project file_selection.toml.
4.1 Environment variables
| Variable | Default | Read in | Purpose |
|---|---|---|---|
OPENAI_API_KEY |
— | main.py, ai.py |
OpenAI / Azure auth. Loaded from .env if unset. |
ANTHROPIC_API_KEY |
— | main.py |
Anthropic (Claude) auth. Loaded from .env if unset. |
MODEL_NAME |
gpt-4o |
main.py |
Default value for --model. |
OPENAI_API_VERSION |
2024-05-01-preview |
ai.py |
Azure OpenAI API version. |
LOCAL_MODEL |
unset | main.py |
When set, prints $0.0 cost instead of computing one. |
EDITOR |
unset | file_selector.py |
Preferred editor for interactive file selection. |
GPTE_TEST_MODE |
unset | file_selector.py |
Internal: forces file selection to read from the saved TOML (used by tests). |
Note
Key loading is intentionally redundant:
load_env_if_needed()callsload_dotenv()and thenload_dotenv(<cwd>/.env)for each key "for legacy reasons." The effect is that a.envin the current directory is always honored when the variable isn't already exported.
4.2 gpt-engineer.toml (project configuration)
An optional TOML file at the project root, parsed by Config.from_toml() in core/project_config.py. It is primarily consumed by the related gptengineer.app service but is read by the CLI's file selector when present. Full schema:
[run]
build = "npm run build"
test = "npm run test"
lint = "quick-lint-js"
# format = "..." # also supported
[paths]
base = "./frontend" # base directory to operate in (for monorepos)
src = "./src" # source dir (under base) used as LLM context
[gptengineer-app] # namespace for gptengineer.app
project_id = "..." # required if this section is present
openapi = [ # optional list of OpenAPI schemas used as context
{ url = "https://api.gptengineer.app/openapi.json" },
{ url = "https://some-color-translating-api/openapi.json" },
]
| Section / key | Type | Notes |
|---|---|---|
[run] build / test / lint / format |
string | Project commands |
[paths] base |
string | Base dir for monorepos |
[paths] src |
string | Source dir, relative to base, used as context |
[gptengineer-app] project_id |
string | Required when the section exists (assertion enforced) |
[gptengineer-app] openapi |
list of {url} |
OpenAPI schemas provided as LLM context |
Config.to_toml() writes back only values that are explicitly set or differ from defaults, preserving the existing TOML document via tomlkit.
4.3 file_selection.toml (improve mode)
Written into <project>/.gpteng/memory/ during improve mode. Lines marked # "<path>" = "selected" are deselected; uncommenting includes the file. A [linting] section toggles black:
[linting]
"linting" = "off" # default behaviour is linting ON
4.4 Tuning constants
| Constant | Value | Location | Effect |
|---|---|---|---|
MAX_EDIT_REFINEMENT_STEPS |
2 |
core/default/constants.py |
Diff-correction retry passes in improve mode |
MAX_SELF_HEAL_ATTEMPTS |
10 |
tools/custom_steps.py |
Self-heal execute/fix iterations |
diff_timeout |
3 (s) |
CLI flag → chat_to_files.parse_diffs |
Regex timeout for diff parsing |
| backoff | max_tries=7, max_time=45 |
ai.backoff_inference |
Exponential backoff on RateLimitError |
Claude max_tokens_to_sample |
4096 |
ai._create_chat_model |
Anthropic output cap |
Vision max_tokens |
4096 |
ai._create_chat_model |
Vision model output cap |
5. On-Disk Layout & State
gpt-engineer keeps all state on the filesystem — there is no database or external store. State for a project lives under a hidden .gpteng/ directory inside that project.
<project>/
├── prompt # your instructions (input)
├── <generated source files> # output
├── run.sh # generated entrypoint (ENTRYPOINT_FILE)
└── .gpteng/ # META_DATA_REL_PATH
├── file_selection.toml # improve-mode file picker state
└── memory/ # MEMORY_REL_PATH = .gpteng/memory
└── logs/
├── all_output.txt # CODE_GEN_LOG_FILE
├── improve.txt # IMPROVE_LOG_FILE
├── diff_errors.txt # DIFF_LOG_FILE
├── debug_log_file.txt # DEBUG_LOG_FILE
└── gen_entrypoint_chat.txt # ENTRYPOINT_LOG_FILE
Path constants are defined in core/default/paths.py:
| Constant | Value |
|---|---|
META_DATA_REL_PATH |
.gpteng |
MEMORY_REL_PATH |
.gpteng/memory |
ENTRYPOINT_FILE |
run.sh |
PREPROMPTS_PATH |
<package>/preprompts |
Other state files written outside .gpteng/:
| File | Location | Purpose |
|---|---|---|
.gpte_consent |
working directory | Stores true if you opted into telemetry |
gpt_engineer_user_id.txt |
system temp dir | Anonymous session id for telemetry |
.langchain.db |
working directory | SQLite LLM response cache (--use_cache) |
clipboard.txt |
working directory | Last clipboard-mode payload |
DiskMemory.archive_logs() rotates prior logs at the start of each run so history is preserved across invocations.
6. The AI Wrapper (core/ai.py)
The AI class is the single point of contact with language models. Understanding it is key to integrations and to supporting new providers.
6.1 Provider selection
AI._create_chat_model() chooses the LangChain chat model from the constructor arguments:
if azure_endpoint set -> AzureChatOpenAI (uses OPENAI_API_VERSION, deployment_name=model_name)
elif "claude" in model_name -> ChatAnthropic (max_tokens_to_sample=4096)
elif vision -> ChatOpenAI (max_tokens=4096)
else -> ChatOpenAI
All variants enable streaming and attach a StreamingStdOutCallbackHandler so generation appears live in the terminal.
6.2 Vision detection
vision is True when the model name contains vision-preview, or contains gpt-4-turbo without preview, or contains claude. When the active model is non-vision, the CLI strips image URLs from the prompt before sending.
6.3 Message handling
start(system, user, *, step_name)seeds a conversation and callsnext().next(messages, prompt=None, *, step_name)appends, optionally collapses consecutive same-role messages (for non-vision models), runs inference, and records token usage.backoff_inference()wrapsllm.invoke()with@backoff.on_exception(backoff.expo, openai.RateLimitError, max_tries=7, max_time=45).serialize_messages()/deserialize_messages()persist conversation history as JSON (normalizing LangChain's stricter chunk schema).
6.4 Token accounting & cost
TokenUsageLog (in token_usage.py) counts tokens per step with a tiktoken tokenizer (cl100k_base fallback for non-GPT models), accumulates totals, and can emit a CSV log. usage_cost() returns a USD estimate only for OpenAI models (is_openai_model() checks for gpt in the name); otherwise it returns None. Vision images are costed via num_tokens_for_base64_image(), which replicates OpenAI's tile-based image token formula using Pillow to measure dimensions.
At the end of a run, main.py prints one of:
Total api cost: $ <amount> # OpenAI model
Total api cost: $ 0.0 since we are using local LLM. # LOCAL_MODEL set
Total tokens used: <n> # non-OpenAI, non-local
7. The Generation Pipeline (Internals)
The pipeline is a set of pure-ish functions in core/default/steps.py (and tools/custom_steps.py), composed by CliAgent.
7.1 System prompts (preprompts/)
The AI's behavior is defined by eight template files loaded by PrepromptsHolder. They are plain text with no extension:
| Preprompt | Role |
|---|---|
roadmap |
Frames the task: "You will get instructions for code to write… write a very long answer." |
generate |
Demands step-by-step reasoning, then full file output; embeds FILE_FORMAT. |
file_format |
Defines the FILENAME + fenced-code output contract for new code. |
file_format_diff |
Defines the strict unified-git diff contract for edits (the rules that make diffs apply cleanly). |
file_format_fix |
Variant used when fixing errors. |
improve |
Improve-mode framing; embeds file_format_diff. |
philosophy |
Coding conventions (one class per file, requirements.txt for Python, package.json for Node, pytest/dataclasses, etc.). |
clarify |
Drives clarify mode: ask one question or say "Nothing to clarify." |
entrypoint |
Instructs the model to emit terminal commands for run.sh (no global installs, no sudo, no placeholders). |
The generate system prompt is assembled as:
roadmap + generate(FILE_FORMAT := file_format) + "\nUseful to know:\n" + philosophy
and the improve system prompt swaps in improve(FILE_FORMAT := file_format_diff).
Tip
--use-custom-prepromptscopies these templates into<project>/preprompts/(viaget_preprompts_path), letting a project override the AI's identity and conventions persistently. This is the supported customization seam — prefer it over forking.
7.2 Generate flow (gen_code → gen_entrypoint → execute_entrypoint)
gen_codesends the generate system prompt + user prompt; parses the reply withchat_to_files_dict()(a(\S+)\n\s*```...```` regex) into aFilesDict. Logs toall_output.txt`.gen_entrypointasks the model for a unix script that installs deps and runs the code (default instruction if noentrypoint_promptis given), extracts fenced code intorun.sh. Logs togen_entrypoint_chat.txt.execute_entrypointprints the script, promptsDo you want to execute this code? (Y/n), and on confirmation runsbash run.shvia the execution environment.
7.3 Improve flow (improve_fn → _improve_loop → salvage_correct_hunks)
improve_fnbuilds a message stack: improve system prompt + the selected files (FilesDict.to_chat(), which prepends line numbers) + the user prompt. Logs uploaded files todebug_log_file.txt._improve_loopcalls the model, thensalvage_correct_hunks, retrying up toMAX_EDIT_REFINEMENT_STEPS(2) times while feeding back any malformed-diff errors.salvage_correct_hunksparses diffs withparse_diffs()(timeout-boundedregex), validates each non-new-file hunk against the real file viaDiff.validate_and_correct(), then applies them withapply_diffs().
7.4 Diff validation & correction (core/diff.py)
This is the most intricate part of the codebase and the reason LLM edits apply reliably. Hunk.validate_and_correct():
- Locates the hunk's start line in the original file using a fuzzy
is_similar()comparison (character-overlap ratio ≥ 0.9, whitespace/case-insensitive). - Detects and repairs two common LLM mistakes: skipped context lines (re-inserts them) and spurious extra lines (drops them), choosing between them by comparing forward-block similarity ratios.
- Relabels misplaced comment lines as additions.
- Recomputes hunk header line numbers and offsets after correction so the resulting diff is internally consistent.
Invalid hunks that cannot be salvaged are printed (Invalid Hunk NO.x) and removed rather than aborting the whole patch.
7.5 Alternative steps (tools/custom_steps.py)
| Function | Substitutes for | Behavior |
|---|---|---|
clarified_gen |
gen_code |
Loops on the clarify preprompt, gathering answers until the model says "Nothing to clarify," then generates. |
lite_gen |
gen_code |
Single ai.start() call with the raw prompt + file_format; no roadmap/philosophy framing. |
self_heal |
execute_entrypoint |
Runs run.sh; on non-zero (and non-2) exit, feeds stdout/stderr back through improve_fn, up to 10 times. |
8. Security
Caution
gpt-engineer's core function is to write and execute code produced by a language model. This is powerful and inherently risky. The guidance below is essential reading before running it on any machine that holds data or credentials you care about.
8.1 Arbitrary code execution (by design)
execute_entrypoint() runs bash run.sh — commands authored by the LLM. There is a Do you want to execute this code? (Y/n) confirmation, but self-heal mode bypasses per-attempt confirmation and executes up to 10 times automatically. Mitigations:
- Run inside a container or disposable VM (see Section 9). The bundled Docker image isolates execution to a mounted project directory.
- Always read
run.shbefore confirming. Decline (n) when in doubt. - Avoid
--self-healon hosts with sensitive state.
8.2 Path traversal in file writing
FileStore.push() (and DiskMemory) write files using paths that originate from LLM output. A community report (issue #1346) describes a path-traversal risk where LLM-generated filenames could escape the working directory and write arbitrary files. Treat the project directory as a trust boundary:
- Run generation as an unprivileged user.
- Prefer container execution where the writable mount is scoped to
/project. - Review generated file paths, not just file contents, before execution.
Warning
This behavior is not unique to one mode — any flow that writes a
FilesDictto disk relies on the LLM's filenames. Containerization is the most robust mitigation.
8.3 Telemetry & data handling
applications/cli/collect.py can send "learning" data (prompt, model, config, logs, and your review answers) to a RudderStack endpoint to help improve the tool. Important facts for operators:
- It is opt-in.
check_collection_consent()only sends data if.gpte_consentcontainstrue; otherwise the user is prompted. - The RudderStack
write_keyanddataPlaneUrlare hardcoded incollect.py. - Disable by answering
n, or by deleting.gpte_consent. For fleet deployments, pre-create.gpte_consentabsent/empty, or stripcollect.pycalls. - Payloads are truncated to RudderStack's 32 KB event limit (
collect_learningstrims oversized logs).
Important
In regulated or air-gapped environments, audit and disable telemetry explicitly. Logs sent can include prompt text and session logs.
8.4 Secrets
API keys are read from the environment or a .env file. The .env.template ships placeholder values only. Standard hygiene applies: keep .env out of version control, scope keys narrowly, and prefer short-lived keys for shared runners.
8.5 Docker permission note
docker/entrypoint.sh runs chown -R nobody:nogroup and chmod -R 777 on generated files (except the prompt file) so host users can access container output. World-writable output is convenient but loose — tighten it if the host is multi-tenant.
9. Deployment (Docker)
Running gpt-engineer in Docker is the recommended way to contain code execution.
9.1 Image
docker/Dockerfile is a two-stage build on python:3.11-slim:
- Builder stage installs
tk,tcl,curl,git, thenpip install --no-cache-dir -e .. - Final stage copies site-packages and binaries from the builder, copies the app, and sets
ENTRYPOINT ["bash", "/app/entrypoint.sh"].
docker/entrypoint.sh invokes gpt-engineer /project "$@" against a mounted /project directory, then fixes output permissions.
9.2 Build & run with the Docker CLI
docker build --rm -t gpt-engineer -f docker/Dockerfile .
docker run -it --rm \
-e OPENAI_API_KEY="YOUR_OPENAI_KEY" \
-v ./your-project:/project \
gpt-engineer
Running gpt-engineer in /project
...
Do you want to execute this code? (Y/n)
The mounted directory must contain a prompt file. Any flags after the image name are passed straight through to gpt-engineer.
9.3 Docker Compose
docker-compose.yml defines a single gpt-engineer service with stdin_open/tty for interactivity, an env_file: .env, and a volume mapping ./projects/example:/project:
docker compose -f docker-compose.yml build
docker compose run --rm gpt-engineer
Edit the volumes entry to point at your own project, and provide the API key via .env or an environment: override.
9.4 Debugging the image
docker run -it --entrypoint /bin/bash gpt-engineer
This opens a shell inside the container so you can inspect the environment manually.
10. Operations
10.1 Running locally (Makefile)
The Makefile provides three convenience targets:
| Target | Action |
|---|---|
make help |
Print usage |
make install |
poetry install + install pre-commit hooks + farewell message |
make run <name> |
poetry run gpt-engineer projects/<name> |
make cloc |
Count lines of code (excludes vendored/benchmark dirs) |
10.2 Logs & diagnostics
Per-project logs live in <project>/.gpteng/memory/logs/. The most useful for incident triage:
debug_log_file.txt— uploaded files, prompt, and the full console capture from improve mode (including stack traces).diff_errors.txt— per-hunk validation problems from the diff engine.all_output.txt/improve.txt— full step transcripts.
gpte --sysinfo prints OS, OS version, architecture, Python version, and the full pip list, then exits — attach this to bug reports.
10.3 Cost & token control
--use_cacheenablesSQLiteCache(.langchain.db)so identical requests are free on rerun.--litereduces prompt overhead for small tasks.- Token totals and (for OpenAI) USD cost print at the end of each run; the per-step CSV is available via
TokenUsageLog.format_log().
10.4 Rate limits
Inference is wrapped in exponential backoff (max_tries=7, max_time=45 s) on openai.RateLimitError. Persistent throttling beyond that window surfaces as a RateLimitError to the user.
11. Benchmarking (bench)
gpt-engineer installs a separate bench console script (gpt_engineer/benchmark/__main__.py, a Typer app) for evaluating agent implementations against public datasets.
bench PATH_TO_AGENT [BENCH_CONFIG] [--yaml-output FILE] [--verbose]
| Argument / option | Default | Purpose |
|---|---|---|
PATH_TO_AGENT |
(required) | A Python file exposing a default_config_agent() function |
BENCH_CONFIG |
benchmark/default_bench_config.toml |
Selects which benchmark tasks to run |
--yaml-output |
none | Write per-task results to a YAML file |
--verbose |
off | Verbose output |
Currently supported benchmarks are APPS and MBPP (loaded via the datasets dependency). The agent under test is imported dynamically with importlib. A starter agent template is available in the project's gpte-bench-template repository.
Note
benchdynamically imports and executes the agent module you point it at. Only run it against agent code you trust.
12. Code Quality & Conventions
| Aspect | Detail |
|---|---|
| Formatter | black (pinned 23.3.0), config in [tool.black] (target-version = py310) |
| Linter | ruff (select = ["F","E","W","I001"], ignores E501, E722) |
| Type checking | mypy 1.3.0 |
| Pre-commit | black, ruff --fix, plus check-toml, check-yaml, detect-private-key, EOF/whitespace fixers; fail_fast: true |
| Tests | pytest; marker requires_key flags tests needing a real OPENAI_API_KEY (deselect with -m "not requires_key") |
| Docstrings | NumPy-style throughout; enforced culturally (see sweep.yaml rules) |
| Docs | Sphinx on Read the Docs (.readthedocs.yaml, Python 3.11, poetry install --with docs, docs/create_api_rst.py pre-build) |
The codebase has good test coverage around the fragile parts: tests/core/ exercises the diff engine (test_salvage_correct_hunks.py), chat_to_files, token usage, and the disk-backed memory/execution environments; tests/applications/cli/ covers the CLI agent, file collection, consent, and the main entrypoint across all modes.
13. Extending gpt-engineer
Common extension points, in order of how cleanly they're supported:
- Override the system prompts. Use
--use-custom-preprompts(or ship apreprompts/folder) to change conventions, language defaults, or the AI's role — no code changes. - Swap step functions. Provide your own
code_gen_fn,improve_fn, orprocess_code_fntoCliAgent/SimpleAgent. This is howclarify/lite/self-healare implemented. - Implement a
BaseExecutionEnv. ReplaceDiskExecutionEnvto run generated code in a sandbox, remote host, or container instead of a local subprocess. The interface (run,popen,upload,download) is deliberately small. - Implement a
BaseMemory. ReplaceDiskMemoryto store project state somewhere other than the local filesystem. - Add a provider. Extend
AI._create_chat_model()with a new branch returning the appropriate LangChain chat model, and updatevision/is_openai_modelheuristics as needed.
Tip
Embedding gpt-engineer as a library is best done through
SimpleAgent(core/default/simple_agent.py) rather than the CLI'sCliAgent, sinceSimpleAgenthas no CLI/telemetry/file-selection coupling.
14. Potential Improvements & Tech Debt
Observations drawn directly from the source at this commit:
- Unpinned
langchain_openai = "*". A floating major dependency in a project whose token-cost code already works around one LangChain import move. Pin the LangChain stack for reproducible builds. - Path-traversal exposure (issue #1346). File writes trust LLM-supplied paths. A sanitizing/normalization layer in
FileStore.push()would harden the default (non-Docker) path. - Hardcoded telemetry credentials. The RudderStack
write_keylives in source. A config/env toggle (or a build flag to compile it out) would suit enterprise deployments better than the current opt-in file. - Provider/vision detection by substring. Model routing keys off substrings like
"claude","gpt-4-turbo", and"vision-preview". New model names (e.g., OpenRouter routing, Gemini, Ollama — issues #1321, #1319) don't fit cleanly; a provider registry would scale better. run.sh-centric execution. The pipeline assumes a unixbashentrypoint; Windows execution leans on WSL/Docker. A pluggable entrypoint strategy would broaden native support.- World-writable Docker output (
chmod -R 777inentrypoint.sh) trades safety for convenience.
15. Quick Reference
Console scripts (from pyproject.toml)
| Command | Target | Purpose |
|---|---|---|
gpt-engineer, ge, gpte |
applications.cli.main:app |
Main CLI |
bench |
benchmark.__main__:app |
Agent benchmarking |
gpte_test_application |
tests.caching_main:app |
Test harness (internal) |
Key paths
| Path | Meaning |
|---|---|
<project>/prompt |
User instructions (input) |
<project>/run.sh |
Generated entrypoint |
<project>/.gpteng/memory/logs/ |
Step transcripts |
<project>/.gpteng/memory/file_selection.toml |
Improve-mode selection |
.gpte_consent |
Telemetry opt-in flag |
.langchain.db |
LLM response cache |
Tuning knobs
| Knob | Default | Where |
|---|---|---|
--diff_timeout |
3 s | CLI |
MAX_EDIT_REFINEMENT_STEPS |
2 | constants.py |
MAX_SELF_HEAL_ATTEMPTS |
10 | custom_steps.py |
| backoff | 7 tries / 45 s | ai.py |
Environment variables
OPENAI_API_KEY · ANTHROPIC_API_KEY · MODEL_NAME · OPENAI_API_VERSION · LOCAL_MODEL · EDITOR · GPTE_TEST_MODE