curl/curl
Treat this repo as two coupled codebases with one very strict style contract. Read the internals docs before the code — docs/internals/ explains the four architectural ideas (connection filters, client writers, client readers, the multi state machine) that the code assumes you already know. Style is machine-enforced: `scripts/checksrc.pl` runs in CI and by default in debug builds, and a style violation fails the build before your logic is ever reviewed. Anything user-visible needs a matching curldown doc and usually a test case, and several files are generated and must not be hand-edited. The safest edits are additive table rows; the riskiest are changes to lib/multi.c, lib/url.c, lib/sendf.c, or lib/cfilters.c, which every protocol depends on.
- Read first, in this order: docs/internals/README.md and the four core internals docs (CONNECTION-FILTERS.md, CLIENT-WRITERS.md, CLIENT-READERS.md, MID.md), then src/tool_main.c and src/tool_operate.c for the tool, then lib/easy.c and lib/multi.c for the library.
- Style is non-negotiable and automated: docs/internals/CODE_STYLE.md is enforced by `scripts/checksrc.pl`, invoked via `make checksrc`, run automatically after `./configure --enable-debug`, and gated in CI by `scripts/checksrc-all.pl`.
- `make lint` is the full pre-push check: it runs `scripts/badwords-all`, `make checksrc` across lib/src/tests/include/examples/projects, and `scripts/spacecheck.pl`.
- Do not hand-edit generated files: src/tool_hugehelp.c is produced by src/mkhelp.pl from the manpage during the build, and src/tool_listhelp.c is likewise generated option-help data.
- Docs are written in curldown (a markdown dialect with a YAML-ish front matter carrying `Title`, `Section`, `Added-in`, `See-also`), documented in docs/CURLDOWN.md and converted by scripts/managen; the checkdocs workflow validates them.
- Adding a test means creating tests/data/testNNNN in the XML-like format and adding it to the numerically-ordered `TESTCASES` list in tests/data/Makefile.am — the file is not picked up automatically.
- To run tests: `make test` (quiet) from the top, or drive the harness directly with `TFLAGS` — `cd tests && ./runtests.pl 1 to 200`, keyword selection like `FTPS` or `!feat:proxy`, `-t` for torture, and `make pytest` for the HTTP/2-3 python suite.
- Public ABI is a hard boundary: include/curl/curlver.h carries the version macros, docs/libcurl/ABI.md states the compatibility promise, and docs/libcurl/symbols-in-versions records when every symbol appeared — new symbols must be added there.
- Any new code must still compile with features disabled: wrap protocol/feature-specific code in the relevant `CURL_DISABLE_*` guard as documented in docs/CURL-DISABLE.md, and use `scripts/randdisable` to sanity-check random combinations.
- Both build systems must be updated together: file lists live in lib/Makefile.inc and src/Makefile.inc for autotools and in lib/CMakeLists.txt / src/CMakeLists.txt for CMake, and configure-vs-cmake.yml exists to catch divergence.
- Do not hand-write RELEASE-NOTES entries: it is maintained by scripts/release-notes.pl and the release flow in docs/RELEASE-PROCEDURE.md (the most recent commit on this branch is literally "RELEASE-NOTES: synced").
- Never file a suspected vulnerability as a normal PR or issue: SECURITY.md and docs/VULN-DISCLOSURE-POLICY.md require private reporting through the curl disclosure process.
- Trap: the `aliases[]` table in src/tool_getparam.c must stay alphabetically sorted by long name — `findlongopt()` binary-searches it, so an out-of-order insertion silently breaks option lookup rather than failing to compile.
- Trap: tool code should call the `curlx_*` wrappers (`curlx_open`, `curlx_fopen`, `curlx_stat`, `curlx_strdup`, `curlx_safefree`, `curlx_dyn_*`) rather than libc directly — the wrappers carry the Windows/VMS/unicode portability that plain libc calls lose.
- Trap: much of the interesting test machinery only exists in debug builds (`DEBUGBUILD`) — `curl_easy_perform_ev()`, `parallel_event()`, `CURL_FORBID_REUSE`, `CURL_MEMDEBUG`, `--test-duphandle` — so a change verified only against a release build has not been exercised by the full suite.
- Safe edit boundaries: adding a row to a registry (schemes, filters, writers, aliases, writeout variables) is low-risk and local; edits inside lib/multi.c's state machine, lib/url.c's connection-reuse matching, or lib/sendf.c's writer stack affect every protocol at once and need the full suite plus pytest. (inferred)