axios/axios
Read `AGENTS.md` first — it is the canonical contributor contract and encodes rules that are not derivable from the code (pre-release changelog/docs staging, `ignore-scripts` safety, dependency policy, error-handling conventions). Then read `lib/core/Axios.js`, `lib/core/dispatchRequest.js`, `lib/core/mergeConfig.js`, and whichever adapter you're touching. The cheapest verification loop is `npm run test:vitest:unit -- tests/unit/<file>.test.js` plus `npx eslint lib/<file>.js`; a full build is only needed for packaging/type changes. The two traps that catch most newcomers are (1) editing `README.md`/`CHANGELOG.md` instead of `PRE_RELEASE_DOCS.md`/`PRE_RELEASE_CHANGELOG.md`, and (2) using ordinary property reads on config where the file uses `own()`/`getSafeProp`, which silently reopens a prototype-pollution hole with no test failure unless you add one.
- Read-first order: `AGENTS.md` (canonical rules, mirrored by the `.github/copilot-instructions.md` stub and `CLAUDE.md`'s one-line `@AGENTS.md` include) → `lib/axios.js` → `lib/core/Axios.js` → `lib/core/dispatchRequest.js` → `lib/core/mergeConfig.js` → the target adapter.
- Unreleased user-visible changes go in `PRE_RELEASE_CHANGELOG.md` under `## Unreleased`, and deferred README/docs-site/migration-guide work goes in `PRE_RELEASE_DOCS.md`; `CHANGELOG.md` (141KB) is release-owned and must not be touched during feature work.
- Install safety: `.npmrc` sets `ignore-scripts=true` and CI uses `npm ci --ignore-scripts`; if husky hooks are needed after a fresh install, run `npm rebuild husky && npx husky` once rather than removing the setting.
- Focused verification commands: `npm run test:vitest:unit -- tests/unit/path.test.js` for one unit file, `npx eslint lib/path/to/file.js` for one source file, `npm run test:vitest:browser:headless` for CI-parity browser runs (requires `npx playwright install` first).
- Never hand-edit `dist/` (generated by Rollup and wiped by `gulp clear`) or `lib/env/data.js` (generated by `gulp version` from package.json) — both are regenerated by the build.
- Any API change must be mirrored in three places: the runtime export list in `lib/axios.js`/`index.js`, `index.d.ts` (ESM types), and `index.d.cts` (CJS `export =` types) — and then exercised by `tests/module/esm` (TS 5.x) and `tests/module/cjs` (TS 4.9).
- Convention trap: config reads that affect behavior must use own-property guards. `lib/adapters/http.js` defines a local `own = (key) => utils.getSafeProp(config, key)` and routes ~20 reads through it; `resolveConfig` and `lib/defaults/index.js` each define their own `own()` helper for the same reason.
- Convention trap: do not use `Function.prototype.bind` directly — the library relies on `lib/helpers/bind.js`, which forwards `arguments` via `apply`, and `createInstance` depends on that behavior for the callable-instance trick.
- Convention trap: never throw raw `Error` from library code — throw `AxiosError(message, code, config, request, response)` or wrap with `AxiosError.from(...)` using a code from the list at the bottom of `lib/core/AxiosError.js`.
- Test-hygiene trap: HTTP fixtures come from `tests/setup/server.js` and must be cleaned up in `try/finally`; leaking a server hangs Vitest. Browser tests replace globals such as XHR and must restore them in cleanup hooks.
- Changes touching URL building, redirects, proxy/env handling, XSRF, socket paths, decompression limits, or adapters require consulting `THREATMODEL.md` (94KB, sections: scope/methodology, runtime threat model, supply-chain threat model) and adding a focused regression test.
- Style boundary for new `lib/**/*.js` files: ESM imports with explicit `.js` extensions, `'use strict';` where neighboring files have it, `Symbol`-keyed internal slots (e.g. `const $internals = Symbol('internals')` in `AxiosHeaders` and `InterceptorManager`) rather than underscore-prefixed properties.
- Dependency changes are effectively out of scope for routine work: runtime deps are four packages and must not grow without discussion, and package/lockfile/Actions update PRs are maintainer/bot-only with a 7-day Dependabot delay enforced by policy plus `lockfile-lint.yml`.
- Commit hygiene is enforced: husky runs a `commit-msg` hook, commitlint uses `@commitlint/config-conventional` with `header-max-length` raised to 130, and lint-staged runs Prettier over `*.{js,cjs,mjs,ts,json,md,yml,yaml}`.
- Default branch is `v1.x` (not `main`): CI triggers on PRs, `lockfile-lint`/`zizmor`/`verify-build-reproducibility` also run on pushes to `v1.x`, and the publish workflow fires on `v1.*.*` tags.