# Contributor handoff — nodejs/node

> Canonical page: https://codevetter.com/unpack/node/agent-handoff

# Contributor handoff — nodejs/node

Scanned commit 976a36a5b6ce737c9e695f6cde8e141427f13737 (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Read `AGENTS.md` first — it is binding policy, not advice, and it forbids an agent from pushing, opening PRs, or posting comments without active human oversight. Code style in `lib/` is not ordinary JavaScript: everything goes through `primordials` to be immune to user monkey-patching, and a custom ESLint plugin enforces it. Before editing, understand that `lib/` is snapshotted at build time, so top-level side effects in bootstrap files have outsized consequences. Nothing in `deps/` should be hand-edited. The realistic verification loop is a full build followed by targeted `tools/test.py` runs, not a fast unit-test cycle.
- `AGENTS.md` requires `Signed-off-by:` from the human contributor and an `Assisted-by: <agent name>` annotation, and explicitly prohibits `Signed-off-by:`/`Co-authored-by:` naming an agent, pushing to any branch or tag, and creating unsupervised PRs or issues. — [AGENTS.md](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/AGENTS.md)
- Read these first, in order: `AGENTS.md`, `CONTRIBUTING.md`, `doc/contributing/primordials.md`, `doc/contributing/cpp-style-guide.md`, and `lib/internal/bootstrap/node.js` (whose header comment is the best single explanation of startup ordering). — [AGENTS.md](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/AGENTS.md) [CONTRIBUTING.md](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/CONTRIBUTING.md) [doc/contributing/primordials.md](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/doc/contributing/primordials.md) [lib/internal/bootstrap/node.js#L1-48](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/bootstrap/node.js#L1-L48)
- Every file in `lib/` destructures from `primordials` at the top (`ArrayPrototypePush`, `StringPrototypeStartsWith`, `ObjectFreeze`, …) instead of using built-in methods directly; new code must match this or `tools/eslint-rules` will reject it. — [lib/internal/vfs/provider_registry.js#L8-10](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/provider_registry.js#L8-L10) [lib/internal/process/permission.js#L3-7](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/permission.js#L3-L7) [doc/contributing/primordials.md](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/doc/contributing/primordials.md) [eslint.config.mjs#L29](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/eslint.config.mjs#L29)
- Never hand-edit `deps/`: `deps/crates/Cargo.toml` states 'This manifest is generated by node-core-utils. Do not modify it directly', and dependency bumps are driven by `tools/dep_updaters/` and scheduled workflows. — [deps/crates/Cargo.toml#L1](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/deps/crates/Cargo.toml#L1) [tools/dep_updaters](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/tools/dep_updaters) [.github/workflows/update-v8.yml](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/.github/workflows/update-v8.yml) [.github/workflows/update-openssl.yml](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/.github/workflows/update-openssl.yml)
- Anything added to `lib/internal/bootstrap/` must be synchronous and must not read argv or env at top level, because it is executed at snapshot-build time; runtime-dependent setup belongs in `pre_execution.js` or a `lib/internal/main/` script. — [lib/internal/bootstrap/node.js#L18-27](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/bootstrap/node.js#L18-L27)
- Verification loop: `./configure && make -j<n>` then `python3 tools/test.py parallel/test-<pattern>` for targeted runs; full validation is `make test-only` (build addons + cctest + jstest + tooltest without rebuilding docs). — [Makefile#L353-361](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/Makefile#L353-L361) [tools/test.py#L1391](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/tools/test.py#L1391) [BUILDING.md](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/BUILDING.md)
- Lint before proposing a change: `make lint` runs js/cpp/md/yaml; `make lint-ci` adds Python lint and a merge-conflict-marker scan across `benchmark deps doc lib src test tools` that fails the build on stray `<<<<<<<`/`>>>>>>>`. — [Makefile#L1734-1752](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/Makefile#L1734-L1752)
- Safe edit boundary: a feature that is JS-only (a new provider, a runner reporter, a stream helper) can be added without touching C++. Anything needing a new syscall, a new option, or a new permission scope requires coordinated edits across `src/node_options.{cc,h}`, `src/node_binding.h`, and `pre_execution.js`. (inferred) — [src/node_options.cc#L690-713](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_options.cc#L690-L713) [src/node_binding.h#L28-81](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_binding.h#L28-L81) [lib/internal/process/pre_execution.js#L499-569](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L499-L569)
- Trap: options are read twice — once at parse time into `EnvironmentOptions` and again in JS via `getOptionValue()` after `refreshRuntimeOptions()`. Caching an option value at JS module scope before that call yields a stale snapshot-time value. — [lib/internal/process/pre_execution.js#L109-113](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L109-L113) [lib/internal/process/pre_execution.js#L366-377](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L366-L377)
- Trap: `permission.js` memoizes `_permission`, `_audit`, and `_ffi` on first read, so an option consulted before `refreshRuntimeOptions()` is frozen for the process lifetime. — [lib/internal/process/permission.js#L13-16](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/permission.js#L13-L16) [lib/internal/process/permission.js#L44-58](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/permission.js#L44-L58)
- Trap: worker option state is not the main thread's — `src/node_worker.cc` overwrites `vfs_load` to false per worker, so a JS-side `getOptionValue('--vfs-load')` reasoning must account for thread identity. — [src/node_worker.cc#L705-710](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_worker.cc#L705-L710)
- Trap: `test/ffi`, `test/sqlite`, `test/addons`, `test/js-native-api`, and `test/node-api` all need a build step (`make build-ffi-tests`, etc.) before `tools/test.py` will pass on them; failures there on a fresh tree usually mean 'not built', not 'broken'. — [Makefile#L323](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/Makefile#L323) [Makefile#L621-626](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/Makefile#L621-L626)
- CI asserts the tree is unchanged after tests run, so any test that writes into the repo (rather than a tmpdir) will fail the Linux workflow even if the assertions pass. — [.github/workflows/test-linux.yml#L89-92](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/.github/workflows/test-linux.yml#L89-L92)
- Use `test/common/index.js` capability predicates (`hasFFI`, `hasDtls`, `hasQuic`, `hasSQLite`, `hasTemporal`, `hasCrypto`) to guard new tests for conditionally-compiled features rather than assuming a full-featured build. — [test/common/index.js#L1021-1031](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/common/index.js#L1021-L1031)
- Public API changes are incomplete without the matching `doc/api/*.md` page and YAML metadata block (`added: vX.Y.Z`, `Stability: 1 - Experimental`), as every subsystem in this tree carries one. — [doc/api/vfs.md#L1-12](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/doc/api/vfs.md#L1-L12) [doc/api/ffi.md#L1-12](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/doc/api/ffi.md#L1-L12) [doc/contributing/api-documentation.md](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/doc/contributing/api-documentation.md)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
