# denoland/deno — codebase unpack

> Canonical page: https://codevetter.com/unpack/deno

This is a deterministic Repo Unpack scan of denoland/deno — a structural map, not a review, security audit, or maintainer-endorsed description.

- Scanned commit: 461f32ec6174d88b7e43654a054d46d67ae2fdab (2026-09-21)
- Last upstream commit: fix(check): pin @types/node and resolve it through the configured registry (#36883)
- Generated by codevetter 1.12.0 on 2026-09-22
- 3997 files scanned · 37.1 MB

## Languages

- TypeScript: 3573 files
- JSON: 2016 files
- JavaScript: 1712 files
- Rust: 1052 files
- TOML: 152 files
- Markdown: 129 files
- CSS: 28 files
- YAML: 27 files

## Repository structure

- tests/ — 1720 files
- libs/ — 801 files
- ext/ — 752 files
- cli/ — 517 files
- runtime/ — 74 files
- tools/ — 69 files
- .github/ — 32 files
- doc/ — 7 files

Probable source entrypoint: `Cargo.toml` (inferred from the tree, not upstream docs)

## Source layout — cli/

- cli/args/ — 3 files
- cli/benches/ — 1 file
- cli/cache/ — 9 files
- cli/examples/ — 1 file
- cli/js/ — 9 files
- cli/lib/ — 25 files
- cli/lsp/ — 38 files
- cli/ops/ — 6 files
- cli/rt/ — 12 files
- cli/rt_desktop/ — 3 files
- cli/schemas/ — 10 files
- cli/snapshot/ — 5 files
- cli/standalone/ — 4 files
- cli/tools/ — 98 files

## Package

- Cargo.toml: null — 0 declared dependencies

## Structural health signals

Average score 5.5/10 across 96 files; 85 hotspots. These are deterministic review leads, not proof of a bug.

## Recent history

- 461f32ec6174 (2026-09-21) fix(check): pin @types/node and resolve it through the configured registry (#36883)
- abd22074e47c (2026-09-17) chore: forward v2.9.7 release commit to main (#36859)
- 685eb3b4b4ff (2026-09-16) fix(cli): preserve double dash before the entrypoint (#36835)
- 057a3da09762 (2026-09-16) fix(ext/http): extract traceparent from Deno.serve regardless of header name case (#36840)
- 800a5e996c00 (2026-09-16) fix(tests): update check_node_builtin_modules output for new @types/node (#36848)

## Overview

This is the Deno runtime monorepo — a Rust workspace (~80 crates) that builds a JavaScript/TypeScript/WebAssembly runtime on V8 and Tokio, plus the `deno` CLI that wraps it with a package manager, type checker, formatter, linter, test runner, LSP server, and single-file-binary compiler. The distinctive shape is three layers: `libs/` holds vendored foundational crates (notably `deno_core` v0.412.0 at `libs/core`, the op2 proc-macro at `libs/ops`, and a hand-rolled zero-allocation flag parser at `libs/cli_parser` that replaced clap with `const` command tables), `ext/` holds 32 self-contained extension crates that expose native ops to JS, and `runtime/`+`cli/` assemble them into the shipped binary. Everything user code touches passes through a capability permission system (`runtime/permissions/lib.rs`, ~11.7k lines) that gates read/write/net/env/sys/run/ffi/import, and the CLI is built around a lazily-memoised dependency-injection container (`CliFactory`) so that `deno fmt` never pays for the npm resolver. It targets JS/TS application developers and, increasingly, Node.js users — a large fraction of `ext/node` exists purely for npm/Node compatibility.

## System map

The binary entry is a nine-line `cli/main.rs` that delegates to `deno::main()` in `cli/lib.rs`, which parses flags, initialises V8, and dispatches a `DenoSubcommand` to a handler under `cli/tools/`. Shared services are constructed lazily through `CliFactory`, a container of `Deferred<T>` once-cells covering caches, resolvers, the file fetcher, npm installer, type checker, and permission container. The JS runtime is assembled in `runtime/worker.rs::common_extensions`, which registers ~35 extension crates from `ext/` in a strict, snapshot-sensitive order; a V8 startup snapshot is baked at build time by `cli/snapshot/build.rs`. Storage is the DENO_DIR: SQLite caches (`cli/cache/caches.rs`) for dep analysis, type checking, code cache, fast-check, and lint/fmt incremental state, plus an HTTP cache and npm package cache. Builds run through `cargo`/`./x`, CI is generated TypeScript (`.github/workflows/ci.ts` → `ci.generated.yml`), and the deployment shape is a single statically-linked executable distributed per-platform.
- `cli/main.rs` is deliberately a 9-line shim calling `deno::main()`; the real entrypoint is `pub fn main()` in `cli/lib.rs`, which sets a panic hook, raises the fd limit, installs the aws-lc-rs rustls crypto provider, and runs everything inside `create_and_run_current_thread_with_maybe_metrics`. — [cli/main.rs#L1-9](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/main.rs#L1-L9) [cli/lib.rs#L863-960](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L863-L960)
- Subcommand dispatch is a single `match flags.subcommand` in `run_subcommand` (cli/lib.rs:124-556) mapping each `DenoSubcommand` variant to a `tools::*` handler wrapped in `spawn_subcommand`, which boxes the future locally specifically to avoid blowing the stack on Windows debug builds. — [cli/lib.rs#L112-556](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L112-L556)
- `DenoSubcommand` is defined in the vendored parser crate at `libs/cli_parser/src/flags.rs:786` with 47 variants (Add, Audit, Bundle, Compile, Deploy, Desktop, Jupyter, Lsp, Pack, Publish, X, …); the CLI re-exports it via `pub use deno_cli_parser::flags::*` in `cli/args/flags.rs`. — [libs/cli_parser/src/flags.rs#L786-833](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/libs/cli_parser/src/flags.rs#L786-L833) [cli/args/flags.rs#L12-14](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/args/flags.rs#L12-L14)
- Flag parsing is a hand-written zero-cost parser, not clap: `libs/cli_parser/src/defs.rs` declares the whole command tree as `const` `ArgDef`/`CommandDef` tables living in `.rodata`, `parse.rs` walks argv against them, and `convert.rs` turns the `ParseResult` into `Flags`; `help.rs` and `completions.rs` render from the same tables. — [libs/cli_parser/src/lib.rs#L1-25](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/libs/cli_parser/src/lib.rs#L1-L25) [libs/cli_parser/src/defs.rs#L1-30](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/libs/cli_parser/src/defs.rs#L1-L30)
- `CliFactory` is the dependency-injection root: `CliFactoryServices` holds ~25 `Deferred<T>` (once-cell) slots — `caches`, `file_fetcher`, `npm_installer_factory`, `resolver_factory`, `type_checker`, `root_permissions_container`, `module_graph_builder` — so a subcommand only constructs the services it actually touches. — [cli/factory.rs#L255-345](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/factory.rs#L255-L345) [cli/factory.rs#L383-440](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/factory.rs#L383-L440)
- The JS runtime's extension set is one ordered `vec![]` in `runtime/worker.rs::common_extensions` (line 1199) listing deno_telemetry, deno_webidl, deno_web, deno_webgpu, deno_image, deno_canvas, deno_fetch, deno_cache, deno_websocket, deno_webstorage, deno_crypto, deno_ffi, deno_net, deno_tls, deno_kv, deno_cron, deno_napi, deno_http, deno_io, deno_fs, deno_os, deno_process, deno_node_crypto, deno_node_sqlite, deno_node, plus crate-local ops; a comment warns ordering must stay in sync with `web_worker.rs`, `snapshot_info.rs`, and `snapshot.rs`. — [runtime/worker.rs#L1199-1262](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/runtime/worker.rs#L1199-L1262)
- `deno_core` is vendored into this repo as `libs/core` (package name `deno_core`, version 0.412.0) rather than consumed from crates.io, alongside `libs/serde_v8`, `libs/ops` (the `#[op2]` proc macro), and `libs/deno_v8`; `libs/dcore/src/main.rs` is a standalone dev harness binary for that core. — [libs/core/Cargo.toml#L1-14](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/libs/core/Cargo.toml#L1-L14) [libs/ops/lib.rs#L25-27](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/libs/ops/lib.rs#L25-L27) [libs/dcore/src/main.rs#L1-30](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/libs/dcore/src/main.rs#L1-L30) [Cargo.toml#L38-60](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/Cargo.toml#L38-L60)
- Persistent state lives in DENO_DIR as SQLite `CacheDB`s created by `cli/cache/caches.rs`: `fmt_incremental_cache_db`, `lint_incremental_cache_db`, `dep_analysis_db`, `fast_check_db`, `node_analysis_db`, `type_checking_cache_db`, and `code_cache_db`; `CliFactory::caches()` pre-warms the relevant ones based on the subcommand. — [cli/cache/caches.rs#L19-140](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/cache/caches.rs#L19-L140) [cli/cache/mod.rs#L1-30](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/cache/mod.rs#L1-L30) [cli/factory.rs#L405-430](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/factory.rs#L405-L430)
- A V8 startup snapshot is produced at build time: `cli/snapshot/build.rs` calls `deno_runtime::snapshot::create_runtime_snapshot` writing `CLI_SNAPSHOT.bin` plus `EXTENSION_RESIDUAL_SOURCES.rs`, and `cli/build.rs` compresses ~60 TypeScript `lib.*.d.ts` declaration files into the binary. — [cli/snapshot/build.rs#L1-40](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/snapshot/build.rs#L1-L40) [cli/build.rs#L9-60](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/build.rs#L9-L60)
- `deno compile` produces a self-contained executable by appending a virtual filesystem and metadata to a base binary: `cli/standalone/binary.rs` defines `DenoCompileBinaryWriter::write_bin` and frames the payload with `MAGIC_BYTES`, using `VfsBuilder`/`VirtualDirectory` from `deno_lib::standalone::virtual_fs`. — [cli/standalone/binary.rs#L367-420](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/standalone/binary.rs#L367-L420) [cli/standalone/binary.rs#L1619-1720](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/standalone/binary.rs#L1619-L1720) [cli/tools/compile.rs#L42-68](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/compile.rs#L42-L68)
- There are two runtime binaries: the full `deno` CLI (`cli/`) and `denort` (`cli/rt_desktop`, v2.7.4) — a trimmed runtime used as the base for compiled output, with its own `binary.rs`, `file_system.rs`, and `code_cache.rs`. — [cli/rt_desktop/Cargo.toml](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/rt_desktop/Cargo.toml) [cli/rt/lib.rs](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/rt/lib.rs) [Cargo.toml#L5-10](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/Cargo.toml#L5-L10)
- The developer entrypoint is `./x`, a shebang script running `tools/x.ts` under Deno; it exposes a `Record<string, Command>` registry with `setup`, `build`, `check`, `test-unit`, `test-node`, `test-compat`, `test-spec`, `test-core`, `test-napi`, `fmt`, `lint`, `lint-js`, `verify`, each documented with LLM-oriented help text. — [x#L1-3](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/x#L1-L3) [tools/x.ts#L100-395](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/x.ts#L100-L395)
- GitHub Actions YAML is generated, not hand-written: every `.github/workflows/*.generated.yml` has a `.ts` sibling, `ci.ts` (2250 lines) defines runner matrices (ubuntu-24.04, ubuntu-24.04-arm, windows-2022, macos-15-intel, macos-14), a `cacheVersion` constant, and PR-label gates `ci-full`/`ci-bench`; `tools/lint.js` enforces freshness via `ensureWorkflowYmlsUpToDate()`. — [.github/workflows/ci.ts#L21-99](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/.github/workflows/ci.ts#L21-L99) [tools/lint.js#L34-44](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/lint.js#L34-L44)
- Formatting is delegated to dprint: `tools/format.js` shells out to `npm:dprint@0.47.2` with `.dprint.json`, covering JS/TS/JSON/Markdown/TOML and Rust in one pass. — [tools/format.js#L1-22](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/format.js#L1-L22) [.dprint.json](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/.dprint.json)
- The workspace is declared in the root `Cargo.toml` with ~80 members spanning `cli/*`, `ext/*`, `libs/*`, `runtime/*`, `tests/*` and `tools/bsdiff_helper`; `tests/sqlite_extension` is explicitly excluded because rusqlite's `loadable_extension` feature conflicts with the workspace's `session` feature. — [Cargo.toml#L1-82](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/Cargo.toml#L1-L82)

## Feature catalog

The CLI surface is unusually broad for a runtime: beyond `run`/`eval`/`repl`/`serve`, it ships a full npm/JSR package manager (`add`, `remove`, `install`, `outdated`, `why`, `audit`, `link`, `pack`, `publish`), a TypeScript type checker, dprint-backed formatter, deno_lint-backed linter with a JS plugin API, a test runner with leak sanitizers and coverage, a benchmarking harness, a documentation generator, a Jupyter kernel, an LSP server, a single-binary compiler, and a Deno Deploy client that bootstraps itself from JSR at runtime. Extensions in `ext/` expose the user-visible Web and Node APIs: fetch, WebSocket, WebGPU, Web Crypto, KV, Cron, FFI, N-API, and a 119-file Node polyfill tree. `deno serve` adds multi-process HTTP serving with `--parallel`, and a tunnel client can expose a local process through Deno's cluster endpoint.
- Package management is consolidated in `cli/tools/pm`, reached from `run_subcommand` for `Add`, `Audit`, `ApproveScripts`, `Remove`, `Link`, `Unlink`, and `Why`; `deno cache` is implemented as a thin alias onto `tools::installer::install_from_entrypoints`. — [cli/lib.rs#L130-190](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L130-L190)
- `deno serve` runs the module as an HTTP server with configurable parallelism: `tools::serve::serve` resolves the main module, optionally opens a browser via `open::that_detached`, and fans out to `parallelism_count(serve_flags.parallel)` workers, each labelled `[serve-worker-nn]` in console output by `99_main.js`. — [cli/tools/serve.rs#L26-80](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/serve.rs#L26-L80) [runtime/js/99_main.js#L974-987](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/runtime/js/99_main.js#L974-L987)
- A module with `export default { fetch }` is auto-detected at bootstrap: `core.addMainModuleHandler` in `bootstrapMainRuntime` calls `registerDeclarativeServer`, warns when run under `deno run`, and errors when run under `deno serve` without it. — [runtime/js/99_main.js#L988-1046](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/runtime/js/99_main.js#L988-L1046)
- `deno deploy` does not embed the deploy client: it fetches `@deno/deploy/meta.json` from JSR at runtime, picks the latest version, and executes `jsr:@deno/deploy@<version>` in a worker with `PermissionsContainer::allow_all` plus a custom `ops::deploy::deno_deploy` extension. — [cli/tools/deploy.rs#L22-101](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/deploy.rs#L22-L101)
- The tunnel feature connects to `tunnel.global.prod.deno-cluster.net:443` (overridable via `DENO_DEPLOY_TUNNEL_ENDPOINT`), authenticates with `Authentication::App { token, org, app }`, prints 'You are connected to https://…' on `Event::Routed`, and injects the tunnel's returned metadata as process env vars. — [cli/lib.rs#L1360-1560](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1360-L1560) [ext/net/tunnel.rs#L32](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/ext/net/tunnel.rs#L32)
- `deno test` supports coverage by creating the coverage dir and exporting `DENO_COVERAGE_DIR` (canonicalised) so spawned subprocesses share it; `--coverage-raw-data-only` plus `--clean` control whether prior contents are wiped. — [cli/lib.rs#L456-482](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L456-L482) [cli/tools/coverage](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/coverage)
- The test runner ships resource/op/timer leak sanitizers: `cli/tools/test/sanitizers.rs` diffs `RuntimeActivityStats` across a test, spins the event loop up to `MAX_SANITIZER_LOOP_SPINS` (16), and tracks `LeakKey::{AsyncOp,Resource,Timer,Interval}` so leaks escaping a sanitizer-ignoring test aren't misattributed to later tests. — [cli/tools/test/sanitizers.rs#L1-60](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/test/sanitizers.rs#L1-L60) [cli/tools/test/mod.rs](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/test/mod.rs)
- A Jupyter kernel is built in: `DenoSubcommand::Jupyter` routes to `tools::jupyter`, and the kernel-side JS (`40_jupyter.js`, `jupyter_kernel.js`) is lazy-loaded into the worker by `CliMainWorkerFactory::create_custom_worker` when `needs_test_modules` is set. — [cli/lib.rs#L255-258](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L255-L258) [cli/worker.rs#L672-692](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/worker.rs#L672-L692) [cli/ops/jupyter.rs](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/ops/jupyter.rs)
- The LSP is a tower-lsp server started by `cli::lsp::start()` over stdio, with ~30 modules including `ts_server.rs` (the largest, driving TypeScript), `diagnostics.rs`, `completions.rs`, `registries.rs` for import completions, and `parent_process_checker.rs` to exit when the editor dies. — [cli/lsp/mod.rs#L1-45](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lsp/mod.rs#L1-L45) [cli/lsp/language_server.rs#L293](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lsp/language_server.rs#L293)
- `deno publish` supports GitHub Actions OIDC: when `auth::is_gha()` and `gha_oidc_token()` are present and `DISABLE_JSR_PROVENANCE` is unset, it exchanges the Actions ID token for a `githuboidc <token>` authorization and attaches provenance. — [cli/tools/publish/mod.rs#L753-800](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/publish/mod.rs#L753-L800) [cli/tools/publish/mod.rs#L1193-1195](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/publish/mod.rs#L1193-L1195)
- Node compatibility is the largest single extension: `ext/node` (~6 MB of source) declares `deno_core::extension!(deno_node, …)` with ops for blocklists, buffers, DNS, module hooks, and a `polyfills/` directory of 119 entries covering node:fs, node:http, node:stream, node:child_process, node:cluster, node:repl and more. — [ext/node/lib.rs#L201-230](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/ext/node/lib.rs#L201-L230) [ext/node/lib.rs#L470-530](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/ext/node/lib.rs#L470-L530)
- Most node polyfills are registered as `lazy_loaded_esm` rather than eager `esm` so that non-Node `deno run` programs skip roughly 2 MB of polyfill deserialization; `node:module`, `node:process`, `node:stream`, `node:net`, `node:tty` and `node:repl` are each explicitly mapped. — [ext/node/lib.rs#L471-520](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/ext/node/lib.rs#L471-L520)
- Deno can masquerade as Node: `node_compat_shim::maybe_rewrite_node_arg0` translates Node CLI args when the binary is invoked through a `node` symlink, and `ensure_node_on_path` creates a `node` shim inside DENO_DIR and prepends it to `PATH` for subcommands that may spawn Node (e.g. Next.js Turbopack). — [cli/node_compat_shim.rs#L1-30](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/node_compat_shim.rs#L1-L30) [cli/node_compat_shim.rs#L87-180](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/node_compat_shim.rs#L87-L180) [cli/lib.rs#L1023-1045](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1023-L1045)
- `deno task` is a real shell interpreter, not a passthrough: `cli/task_runner.rs` parses scripts with `deno_task_shell::parser::parse` and registers custom `ShellCommand` implementations — `NpmCommand`, `NpxCommand`, `NodeCommand`, `NodeGypCommand`, `DenoCommand` — that rewrite invocations back onto the current `deno` executable. — [cli/task_runner.rs#L178-230](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/task_runner.rs#L178-L230) [cli/task_runner.rs#L306-460](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/task_runner.rs#L306-L460)
- Experimental/warned-on surfaces are explicitly labelled at dispatch: `deno bundle` prints '⚠️ deno bundle is experimental', `deno bump-version` prints a yellow experimental warning, and `deno vendor` is a hard error pointing at the Deno 1.x→2.x migration guide. — [cli/lib.rs#L161-168](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L161-L168) [cli/lib.rs#L515-527](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L515-L527)

## Data flow

Input boundaries are argv (parsed into `Flags` by the const-table parser), environment variables and `.env` files, config files (`deno.json`/`package.json`) discovered through the workspace factory, and remote sources fetched over HTTP from JSR and npm registries. `CliFactory` owns the service graph; `ModuleGraphBuilder` builds a `deno_graph::ModuleGraph` from roots, `TypeChecker` optionally validates it against a TSC-backed cache, and `CliEmitter` transpiles TypeScript to JavaScript. At runtime, `CliModuleLoader::load` serves module source out of the prepared graph (or delegates to JS load hooks, or to an eszip), and V8 executes it. Every side-effecting op re-enters Rust through `PermissionsContainer`, which is the single state owner for capability decisions. Output boundaries are stdout/stderr (via `deno_print`/`DrawThread`), the DENO_DIR SQLite and HTTP caches, the lockfile, OpenTelemetry exporters, and for `compile`, a written executable.
- argv → `Flags` happens in `resolve_flags_and_init`, which special-cases the `COMPLETE` env var for shell completions, distinguishes `--version` from `-V` before parsing, and only then calls `flags_from_vec_with_initial_cwd`. — [cli/lib.rs#L967-1000](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L967-L1000)
- `.env` files are loaded into the process environment before any service construction: `load_env_variables_from_env_files(&cwd, files, flags.log_level)` runs right after flag parsing, and `WatchEnvTracker::snapshot()` captures pre-load state when `--watch` is active. — [cli/lib.rs#L1000-1017](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1000-L1017) [libs/dotenv](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/libs/dotenv)
- Unstable feature configuration is merged from three sources in order: CLI flags, `flags.unstable_config.fill_with_env(&sys)`, and the `DENO_COMPAT` env var which force-enables node compat; `DENO_CONDITIONS` similarly seeds `flags.node_conditions`. — [cli/lib.rs#L1053-1070](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1053-L1070)
- Module loading is two-phase: `ModuleLoadPreparer::prepare_module_load` builds the graph with npm resolution (`build_graph_roots_with_npm_resolution`), validates roots, runs `TypeChecker::check` only when `type_check_mode().is_true()` and the graph wasn't already checked, then writes the lockfile *after* type checking because checking can discover `@types/node`. — [cli/module_loader.rs#L193-300](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/module_loader.rs#L193-L300)
- `CliModuleLoader::load` has three source paths in priority order: an eszip loader when `maybe_eszip_loader` is set, the JS module-hook bridge (`hook_registry.push_load`) for async non-CJS loads, and otherwise the prepared graph; it records every specifier into `loaded_files` for watch-mode invalidation. — [cli/module_loader.rs#L1428-1520](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/module_loader.rs#L1428-L1520)
- The load-hook bridge deliberately skips CJS modules because `Module._load` already runs `executeLoadHookChain` synchronously — going through both would invoke user hooks twice. — [cli/module_loader.rs#L1445-1463](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/module_loader.rs#L1445-L1463)
- Remote source fetching flows through `CliFileFetcher`, which takes a `FetchPermissionsOptionRef` per call; `deploy` explicitly passes `AllowAll` plus `CacheSetting::RespectHeaders` so jsr.io's `cache-control: max-age=60` is honoured instead of pinning the first cached copy forever. — [cli/tools/deploy.rs#L59-76](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/deploy.rs#L59-L76) [cli/file_fetcher.rs](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/file_fetcher.rs) [cli/factory.rs#L553-572](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/factory.rs#L553-L572)
- npm resolution mode determines the read-permission checker: `create_module_loader_factory` picks `NpmRegistryReadPermissionCheckerMode::Byonm`, `::Local(node_modules_dir)`, or `::Global(npm_cache_root)` before constructing `CliModuleLoaderFactory`. — [cli/factory.rs#L1233-1255](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/factory.rs#L1233-L1255)
- The root permission set is derived once from config+flags: `CliFactory::root_permissions_container` builds `Permissions::from_options(desc_parser, cli_options.permissions_options()?)` and wraps it in a `PermissionsContainer` that all workers clone from. — [cli/factory.rs#L1191-1206](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/factory.rs#L1191-L1206) [runtime/permissions/lib.rs#L4132](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/runtime/permissions/lib.rs#L4132)
- Worker construction pre-installs npm packages: `create_custom_worker` collects `NpmPackageReqReference`s from the main module plus preload/require modules and calls `npm_installer.add_package_reqs` with `PackageCaching::Only` under the Lazy strategy or `PackageCaching::All` otherwise. — [cli/worker.rs#L596-640](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/worker.rs#L596-L640)
- For an `npm:` main module, the specifier is rewritten to a resolved bin entrypoint via `resolve_npm_binary_entrypoint`, and the lockfile is flushed with `write_if_changed()` so the next run can reuse the resolution. — [cli/worker.rs#L641-668](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/worker.rs#L641-L668)
- Bootstrap data crosses the Rust→JS boundary as a positional array: `bootstrapMainRuntime(runtimeOptions)` destructures indices 0–19 (denoVersion, location, unstableFeatures, hasNodeModulesDir, argv0, nodeDebug, mode, servePort, serveHost, otelConfig, standalone, nodeClusterUniqueId, …) and then removes the bootstrap object from the global scope. — [runtime/js/99_main.js#L936-1060](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/runtime/js/99_main.js#L936-L1060)
- Telemetry is initialised before any subcommand runs: `deno_telemetry::init(&sys, otel_runtime_config(), otel_config)` is called from `resolve_flags_and_init`, and failure paths report through `deno_telemetry::report_event("boot_failure" | "uncaught_exception", e)` in `run_script`. — [cli/lib.rs#L1077-1084](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1077-L1084) [cli/tools/run/mod.rs#L229-245](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/run/mod.rs#L229-L245)
- Permission decisions can be teed to an audit sink: `DENO_AUDIT_PERMISSIONS=otel` routes each access through `deno_telemetry::handle_log` with `deno.permission.{type,value,stack}` key-values, and any other value is treated as a file path opened with `File::create`. — [cli/lib.rs#L1100-1130](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1100-L1130)
- `deno run -` reads stdin fully into memory and injects it as a synthetic file via `file_fetcher.insert_memory_files(File { url: main_module, … })` so the type checker and graph builder can see it as a normal module. — [cli/tools/run/mod.rs#L249-290](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/run/mod.rs#L249-L290)

## Behavior traces

Three flows dominate. Startup: `main()` → panic hook/logging/fd-limit → optional control-socket handshake → `resolve_flags_and_init` → `init_v8` → `run_subcommand`. Primary action (`deno run`): `tools::run::run_script` → `CliFactory` service warm-up → main-module resolution → npm install → `create_cli_main_worker_factory_with_roots` → `create_main_worker_with_unconfigured_runtime` → `CliMainWorker::run`. Persistence (`deno compile`): `compile_inner` → module graph creation → `DenoCompileBinaryWriter::write_bin` → VFS build → `MAGIC_BYTES`-framed binary written to disk. A fourth path worth knowing is the pre-warmed-runtime handshake on Unix, where `DENO_UNSTABLE_CONTROL_SOCK` lets a parent hand this process an already-initialised `UnconfiguredRuntime` and a replacement argv.
- Startup order in `main()` is: `boot_phase("main start")` → `setup_panic_hook()` → `init_logging(None, None)` → `raise_fd_limit()` / `ensure_stdio_open()` → set prompt callbacks to `DrawThread::hide`/`show` → `maybe_setup_permission_broker()` → install aws-lc-rs → `maybe_rewrite_node_arg0(args)`. — [cli/lib.rs#L863-895](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L863-L895)
- `boot_phase(label)` is a built-in startup profiler: gated on `DENO_STARTUP_PHASES`, it prints `[boot] <label> <elapsed>` to stderr at ~10 checkpoints including 'after init_v8', 'after cli_options', 'after worker_factory', and 'after worker.run (exit)'. — [cli/lib.rs#L841-860](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L841-L860) [cli/tools/run/mod.rs#L183-247](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/run/mod.rs#L183-L247)
- On Unix, `wait_for_start` reads `DENO_UNSTABLE_CONTROL_SOCK`, immediately removes the env var, and may return `(UnconfiguredRuntime, Vec<OsString> args, PathBuf cwd)` — a pre-initialised runtime that causes `main()` to skip `init_v8` entirely. — [cli/lib.rs#L1185-1200](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1185-L1200) [cli/lib.rs#L900-935](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L900-L935)
- V8 flags are resolved in `init_v8`: `DenoSubcommand::Lsp` gets `--stack-size=1024 --max-old-space-size=3072` (matching VS Code), everything else gets `get_default_v8_flags()`; a `--single-threaded` flag in either argv or `V8_FLAGS` env switches to `v8::Platform::new_single_threaded`. — [cli/lib.rs#L1136-1165](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1136-L1165)
- The tunnel is connected before everything else because it sets env vars and OTEL: `flags.tunnel` (or `DENO_CONNECTED`) triggers `initialize_tunnel` prior to unstable-config resolution, and the subcommand is explicitly excluded when it is `Deploy`. — [cli/lib.rs#L1046-1062](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1046-L1062)
- `initialize_tunnel` resolves credentials through a four-way fallback — (DENO_DEPLOY_TOKEN + ORG + APP) → deploy config app + env token → deploy config + keyring token → interactive `auth_tunnel` — and on `Error::Unauthorized` deletes the stored credential and retries once after re-auth. — [cli/lib.rs#L1400-1520](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1400-L1520)
- `auth_tunnel` re-executes the current binary (`env::current_exe()`) as `deno deploy tunnel-login --out <tempfile>`, waits for it, and parses `AuthTunnelOutput` JSON from the temp file; a non-zero exit calls `deno_runtime::exit(1)`. — [cli/lib.rs#L1326-1358](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1326-L1358)
- `run_script` order is: `check_permission_before_script` → watch-mode branch → `CliFactory::from_flags` → `cli_options` → `deno_dir` → `http_client_provider` → `workspace_resolver` → `node_resolver` → background upgrade check → `resolve_main_module_with_resolver` → `maybe_npm_install` → `try_run_npm_bin_executable` → worker factory → `worker.run()`. — [cli/tools/run/mod.rs#L170-247](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/run/mod.rs#L170-L247)
- Before loading any JS, `run_script` checks whether an `npm:` main module resolves to a *native* binary: `resolve_npm_native_bin` resolves the package folder, finds the bin via `tools::x::find_bin_value`, and re-checks file magic with `node_resolver::is_binary` because `read_bin_value` classifies any shebang-less file as `BinValue::Executable`. — [cli/tools/run/mod.rs#L54-168](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/run/mod.rs#L54-L168)
- `check_permission_before_script` warns (but does not fail) when permission flags appear *after* the script argument — a common user error that would otherwise silently pass them to the script as argv. — [cli/tools/run/mod.rs#L29-40](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/run/mod.rs#L29-L40)
- Test/bench/jupyter/lint runtimes get extra JS injected at worker-creation time: `create_custom_worker` calls `lazy_load_es_module_with_code` for `40_test_common.js`, `40_test_snapshot.js`, `40_test.js`, `40_bench.js`, `40_jupyter.js`, `jupyter_kernel.js`, `40_lint_selector.js`, `40_lint.js` when `needs_test_modules` is set (driven by `DenoSubcommand::needs_test()`). — [cli/worker.rs#L668-695](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/worker.rs#L668-L695) [libs/cli_parser/src/flags.rs#L863-878](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/libs/cli_parser/src/flags.rs#L863-L878)
- Under `--watch`, `run_with_watch` drives `util::file_watcher::watch_recv` with `WatcherRestartMode::Automatic`, rebuilding a `CliFactory::from_flags_for_watcher` per iteration; `--watch` is rejected outright for npm packages whose bin is a native executable. — [cli/tools/run/mod.rs#L292-330](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/run/mod.rs#L292-L330)
- The presence of a `WatcherCommunicator` on the factory is load-bearing beyond HMR: a comment in `create_cli_main_worker_factory_with_roots` explains `CliMainWorker::run()` uses it to route `Deno.exit()` through isolate termination rather than `std::process::exit`, keeping `deno serve --watch` alive across exits (issue #7590). — [cli/factory.rs#L1285-1305](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/factory.rs#L1285-L1305) [cli/worker.rs#L80-290](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/worker.rs#L80-L290)
- `deno compile` on a directory triggers framework detection: `compile_inner` treats `source_file == "."` (or a directory path) as a request to detect the framework and synthesise an entrypoint before graph building. — [cli/tools/compile.rs#L69-95](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/compile.rs#L69-L95) [cli/tools/framework.rs](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/framework.rs)
- A spec test step executes as: `run_step` merges test-level and step-level envs → applies variant substitutions → builds a `TestContext` command with args/cwd/commandName/stdin/timeout → `command.run()` → output matched against the `.out` expectation with the wildcard language. — [tests/specs/mod.rs#L560-680](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/specs/mod.rs#L560-L680) [tests/util/lib/wildcard.rs](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/util/lib/wildcard.rs)

## Testing signals

Testing is Rust-driven but mostly JS/JSONC-authored. Five separate cargo test crates each use `file_test_runner` with `harness = false` and a custom `main()`: `specs_tests` (CLI integration via `__test__.jsonc`), `unit_tests` (`tests/unit/*_test.ts`), `unit_node_tests`, `node_compat_tests`, and `integration_tests` (28 Rust files). Web Platform Tests run from a git submodule under `tests/wpt`, and results are uploaded to wpt.fyi and S3 from CI. Each runner computes a content hash of its inputs (`check_ci_hash`) and skips entirely when nothing changed. Coverage gaps are structural rather than accidental: the spec suite exercises the CLI as a black box, so internal Rust units like `CliFactory` wiring, the tunnel client, and `standalone/binary.rs` framing have little direct unit coverage.
- Spec tests are the primary integration suite: `tests/specs/mod.rs::main` collects one test per directory containing `__test__.jsonc` via `TestPerDirectoryCollectionStrategy`, wrapped in a `FileTestMapperStrategy` that expands the manifest's `tests` map into individual cases. — [tests/specs/mod.rs#L266-340](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/specs/mod.rs#L266-L340) [tests/specs/schema.json#L1-60](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/specs/schema.json#L1-L60)
- There are 58 top-level spec categories under `tests/specs/` (add, bundle, cert, check, compile, coverage, cpu_prof, deploy, jsr, jupyter, lockfile, npm, permission, publish, serve, task, watch, workspaces, x, …), each containing many per-directory manifests. — [tests/specs/](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/specs/) [tests/specs/schema.json](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/specs/schema.json)
- The spec runner explicitly blocks agent misuse: if `CLAUDE_CODE_ENTRYPOINT` is set and no filter argument was passed, `main()` panics with 'Running the entire spec test suite from Claude Code is not allowed. Please provide a test filter'. — [tests/specs/mod.rs#L266-279](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/specs/mod.rs#L266-L279)
- Every runner short-circuits on unchanged inputs via `test_util::hash::check_ci_hash`, which hashes `tests/specs`, `tests/util`, `tests/testdata`, `tests/registry`, the `deno` binary, `test_server`, and `denort`; a `CiHashStatus::Skip` returns immediately. — [tests/specs/mod.rs#L280-296](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/specs/mod.rs#L280-L296) [tests/unit/mod.rs#L18-32](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/unit/mod.rs#L18-L32)
- Unit tests are TS files run through cargo: `unit_tests` collects `tests/unit/.*_test\.ts$` with `TestPerFileCollectionStrategy`; `CLAUDE.md` warns they must not be run directly with `./target/debug/deno test` because they depend on the cargo harness setup. — [tests/unit/mod.rs#L18-50](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/unit/mod.rs#L18-L50) [tests/unit/Cargo.toml](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/unit/Cargo.toml) [CLAUDE.md](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/CLAUDE.md)
- Flakiness is first-class: the spec runner threads a shared `FlakyTestTracker` through `run_maybe_flaky_test`, and the `__test__.jsonc` schema has a `flaky: boolean` field plus an `if` field for platform gating (`mac`, `linux`, `windows`, `unix`, `notMacIntel`). — [tests/specs/mod.rs#L26-33](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/specs/mod.rs#L26-L33) [tests/specs/schema.json#L34-56](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/specs/schema.json#L34-L56)
- Spec tests run against a live local HTTP server: `let _http_guard = test_util::http_server();` is held for the duration of the run, and `tests/util/server/` builds the `test_server` binary with `servers/`, `https.rs`, and `npm.rs` fixtures. — [tests/specs/mod.rs#L322-340](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/specs/mod.rs#L322-L340) [tests/util/server/main.rs](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/util/server/main.rs)
- Rust-side integration tests live in `tests/integration/` as 28 files (`lsp_tests.rs`, `npm_tests.rs`, `publish_tests.rs`, `watcher_tests.rs`, `upgrade_tests.rs`, `compile_tests.rs`, `sqlite_extension_tests.rs`, …) in the `integration_tests` crate, with an `upgrade` cargo feature gating upgrade tests. — [tests/integration/Cargo.toml#L1-20](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/integration/Cargo.toml#L1-L20) [tests/integration/mod.rs](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/integration/mod.rs)
- Node.js compatibility is tested against the real Node test suite pulled in as a submodule: CI clones `./tests/node_compat/runner/suite` only for the `node_compat` test crate, and the results are summarised by `tests/node_compat/report.rs` and `slack.ts`. — [.github/workflows/ci.ts#L1418-1420](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/.github/workflows/ci.ts#L1418-L1420) [tests/node_compat/Cargo.toml](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/node_compat/Cargo.toml) [tests/node_compat/report.rs](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/node_compat/report.rs)
- WPT runs on non-tag builds: CI clones `tests/wpt/suite`, writes the hosts file, runs `./tests/wpt/wpt.ts run --all --quiet`, and on release uploads `wpt.json`/`wptreport.json.gz` to `s3://dl-deno-land/wpt/` and to wpt.fyi via `tools/upload_wptfyi.js`. — [.github/workflows/ci.ts#L1638-1730](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/.github/workflows/ci.ts#L1638-L1730)
- Core crate tests run under cargo-nextest, not plain cargo test: `./x test-core` and CI both run `cargo nextest run` across `deno_core`, `deno_v8`, `build-your-own-js-snapshot`, `dcore`, `deno_ops`, `deno_ops_compile_test_runner`, `serde_v8`, `deno_core_testing`, plus a separate `cargo test --doc` pass. — [tools/x.ts#L272-315](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/x.ts#L272-L315) [.github/workflows/ci.ts#L1977-2000](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/.github/workflows/ci.ts#L1977-L2000)
- CI asserts tests do not mutate the working tree: after running a test crate it checks git status and fails with '❌ Git working directory is dirty. Ensure `cargo test` is not modifying git tracked files.' — [.github/workflows/ci.ts#L1498-1525](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/.github/workflows/ci.ts#L1498-L1525)
- Lint is itself partly a test suite: `tools/lint.js` runs clippy plus bespoke checks — `ensureNoNonPermissionCapitalLetterShortFlags`, `ensureDisallowedMethodsEnforced`, `lintBootstraps`, `lintNodePolyfillDenoApis`, `ensureWorkflowYmlsUpToDate`, `ensureNoUnusedOutFiles`, `ensureNoNewTopLevelEntries`, and `checkCopyright`. — [tools/lint.js#L19-55](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/lint.js#L19-L55)
- Test sharding and parallelism are built into the harness: `ShardConfig::from_env()` filters the collected category, and `Parallelism::default().max_parallelism()` drives `file_test_runner::run_tests`. — [tests/specs/mod.rs#L306-338](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/specs/mod.rs#L306-L338)
- The tunnel client, `initialize_tunnel`'s credential fallback chain, and `cli/standalone/binary.rs` binary framing have no dedicated test module in their files — unlike `cli/tools/deploy.rs`, `cli/worker.rs`, and `cli/file_fetcher.rs`, which each carry `#[cfg(test)] mod tests`. (inferred) — [cli/lib.rs#L1360-1560](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1360-L1560) [cli/tools/deploy.rs#L113-130](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/deploy.rs#L113-L130) [cli/worker.rs#L703-710](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/worker.rs#L703-L710) [cli/file_fetcher.rs#L300-320](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/file_fetcher.rs#L300-L320)

## Risk map

The blast radius concentrates in three places: the permission system (an 11.7k-line file that every capability check funnels through), the extension ordering list in `runtime/worker.rs` (silently snapshot-coupled across four files), and the many `unsafe { std::env::set_var(...) }` calls in startup that are only sound because they run before any thread is spawned. Security-sensitive paths include FFI `dlopen`, subprocess spawn with LD_PRELOAD-style env filtering, the permission broker's IPC socket, the Deno Deploy keyring token, the runtime-fetched deploy CLI executed with `allow_all`, and the `node` shim that mutates the process `PATH`. Several performance-motivated lazy-loading decisions (lazy node polyfills, hoisted `registerDeclarativeServer` guard) are fragile in the sense that they encode non-obvious invariants in comments rather than tests.
- `deno deploy` executes code fetched from JSR at runtime with `PermissionsContainer::allow_all` — the version is chosen by `resolve_deploy_cli_version` from `@deno/deploy/meta.json`, so a compromised or unexpected JSR publish would run fully privileged on the user's machine. — [cli/tools/deploy.rs#L59-101](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/deploy.rs#L59-L101)
- Subprocess spawn blocks a real privilege-escalation vector: `check_run_permission` refuses to spawn with any `LD_*`/`DYLD_*` env var set unless `--allow-run` is granted for all, because those allow arbitrary code execution via LD_PRELOAD. — [ext/process/lib.rs#L1524-1560](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/ext/process/lib.rs#L1524-L1560)
- `op_ffi_load` gates on `check_ffi_partial_with_path` and then calls `Library::open` on the (possibly denort-remapped) path — once loaded, the dynamic library runs with full process privileges outside the permission model. — [ext/ffi/dlfcn.rs#L145-175](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/ext/ffi/dlfcn.rs#L145-L175)
- The permission prompter defends against terminal spoofing by escaping bidi and zero-width Unicode formatting controls (U+202E RTL Override, U+2066 isolates, U+200B ZWSP, …) that would otherwise let a malicious path forge the prompt label — the Trojan-Source vector. — [runtime/permissions/prompter.rs#L26-62](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/runtime/permissions/prompter.rs#L26-L62)
- `DENO_PERMISSION_BROKER_PATH` connects permission decisions to an external process over an IPC pipe; a connection failure calls `std::process::exit(87)` with a TODO noting the exit code was randomly chosen and undocumented. — [runtime/permissions/broker.rs#L14-70](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/runtime/permissions/broker.rs#L14-L70) [cli/lib.rs#L829-841](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L829-L841)
- The Deno Deploy token is stored in the OS keyring under service 'Deno Deploy Token' / user 'Deno Deploy' and is read during tunnel setup; on an `Unauthorized` response the code deletes the credential and re-runs interactive auth. — [cli/tools/deploy.rs#L110-112](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/deploy.rs#L110-L112) [cli/lib.rs#L1411-1420](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1411-L1420) [cli/lib.rs#L1520-1540](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1520-L1540)
- Startup performs multiple `unsafe { std::env::set_var(...) }` calls — `DENO_CONNECTED`, `DENO_COVERAGE_DIR`, `DENO_DEPLOY_CLI_SANDBOX`, `PATH`, and every key/value the tunnel server returns in its metadata — each justified only by a comment asserting single-threadedness; adding a thread earlier in startup would make these unsound. — [cli/lib.rs#L1057-1062](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1057-L1062) [cli/lib.rs#L1540-1552](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1540-L1552) [cli/lib.rs#L479-489](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L479-L489) [cli/node_compat_shim.rs#L290-310](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/node_compat_shim.rs#L290-L310)
- The tunnel injects arbitrary server-supplied environment variables into the process: `for (k, v) in metadata.env { std::env::set_var(k, v) }` with no allowlist, so the tunnel endpoint is effectively trusted to configure the local process. — [cli/lib.rs#L1538-1552](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1538-L1552)
- The `node` PATH shim writes a symlink (Unix) or `.exe`-named shim (Windows) into DENO_DIR and prepends that directory to `PATH`, meaning any process spawned by user code — not just Deno — resolves `node` to the Deno binary; correctness depends on the scan finding no real Node first. — [cli/node_compat_shim.rs#L1-30](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/node_compat_shim.rs#L1-L30) [cli/node_compat_shim.rs#L173-310](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/node_compat_shim.rs#L173-L310)
- The extension registration order in `common_extensions` is a cross-file invariant with no automated check: a comment says it must be kept in sync with `runtime/worker.rs`, `runtime/web_worker.rs`, `runtime/snapshot_info.rs`, and `runtime/snapshot.rs`, and a mismatch surfaces as snapshot corruption rather than a compile error. — [runtime/worker.rs#L1206-1212](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/runtime/worker.rs#L1206-L1212) [runtime/snapshot.rs#L59-100](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/runtime/snapshot.rs#L59-L100)
- `ext/node`'s lazy/eager split is a hand-maintained list with a documented trap: an explicit `esm` entry that no eager module imports 'would land in the module map unevaluated and fail snapshot validation with NonEvaluatedModules'. — [ext/node/lib.rs#L468-480](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/ext/node/lib.rs#L468-L480)
- `runtime/permissions/lib.rs` is a single 11,756-line module owning every descriptor type, the allow/deny/prompt state machine, and `PermissionsContainer` — the highest-blast-radius file in the repo for security regressions. — [runtime/permissions/lib.rs#L1-200](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/runtime/permissions/lib.rs#L1-L200) [runtime/permissions/lib.rs#L4132-4160](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/runtime/permissions/lib.rs#L4132-L4160)
- Dead/legacy surfaces still occupy the dispatch table: `DenoSubcommand::Vendor` exists solely to print a removal message and exit 1, and `--unstable` is accepted but warns it was removed in Deno 2.0 with a TODO to hard-error in v2.5. — [cli/lib.rs#L524-528](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L524-L528) [cli/lib.rs#L1090-1098](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1090-L1098)
- The `registerDeclarativeServer` fast path in `99_main.js` encodes a performance optimisation as a behavioural guard — it skips loading ~430 KB of serve/streams modules unless the default export has an own `fetch` — and the comment explicitly notes `dflt == null` must still call through to preserve the existing TypeError. — [runtime/js/99_main.js#L989-1012](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/runtime/js/99_main.js#L989-L1012)
- `deno test --coverage` does `let _ = std::fs::remove_dir_all(coverage_dir)` on a user-supplied path before creating it; the deletion is unconditional (outside the raw-data-only case) and silently ignores errors. — [cli/lib.rs#L456-472](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L456-L472)
- The `NodeCommand` shell command silently rewrites `node script.js` inside `deno task` to `deno run -A --unstable-bare-node-builtins --unstable-detect-cjs --unstable-sloppy-imports --unstable-unsafe-proto script.js` — granting all permissions and four unstable flags that the task author never wrote. — [cli/task_runner.rs#L378-420](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/task_runner.rs#L378-L420)

## Extension points

New native capability is added as an `ext/<name>` crate using `deno_core::extension!` (ops + esm + lazy_loaded_esm), registered into the ordered list in `runtime/worker.rs::common_extensions`, and exposed to JS from the extension's own `.js`/`.ts` files. New CLI surface is added by extending the `const` tables in `libs/cli_parser/src/defs.rs`, adding a `DenoSubcommand` variant in `flags.rs`, a conversion in `convert.rs`, an arm in `run_subcommand`, and a handler module under `cli/tools/`. New shared services are added as `Deferred<T>` fields on `CliFactoryServices` with an accessor method. The `deno task` shell has its own `ShellCommand` registry, the module loader has a JS-level load-hook registry, and the developer tooling itself is extensible via `tools/x.ts`'s command record and `.claude/skills/`.
- An extension is declared with the `deno_core::extension!` macro taking `deps`, `parameters`, `ops = [...]`, `esm = [...]`, `lazy_loaded_esm = [...]`, and `synthetic_esm = [...]` — `ext/node/lib.rs:201` is the most elaborate example, parameterised over `InNpmPackageChecker`, `NpmPackageFolderResolver`, and `ExtNodeSys`. — [ext/node/lib.rs#L201-230](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/ext/node/lib.rs#L201-L230) [ext/node/lib.rs#L468-530](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/ext/node/lib.rs#L468-L530)
- Ops are written with the `#[op2]` proc macro defined at `libs/ops/lib.rs:25`, with the codegen split across `libs/ops/op2/`, `conversion/`, `cppgc.rs`, and `webidl/`, and a dedicated `libs/ops/compile_test_runner` crate that asserts macro expansion still compiles. — [libs/ops/lib.rs#L25-27](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/libs/ops/lib.rs#L25-L27) [libs/ops/op2](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/libs/ops/op2) [Cargo.toml#L50-52](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/Cargo.toml#L50-L52)
- Registering a new extension means adding one line to the `vec![]` in `common_extensions` at the correct position; `.disable()` is available to register ops without activating them, as done for `ops::web_worker::deno_web_worker` in the main worker. — [runtime/worker.rs#L1219-1262](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/runtime/worker.rs#L1219-L1262)
- Adding a CLI subcommand is a five-file change: a `DenoSubcommand` variant + flags struct in `libs/cli_parser/src/flags.rs`, a `CommandDef` in `defs.rs`, a converter in `convert.rs`, an arm in `cli/lib.rs::run_subcommand`, and a handler under `cli/tools/`. — [libs/cli_parser/src/flags.rs#L786-833](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/libs/cli_parser/src/flags.rs#L786-L833) [libs/cli_parser/src/defs.rs#L1-30](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/libs/cli_parser/src/defs.rs#L1-L30) [cli/lib.rs#L124-556](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L124-L556) [cli/tools/mod.rs](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/mod.rs)
- New shared services plug into `CliFactoryServices` as a `Deferred<T>` field plus a `pub fn` accessor using `get_or_try_init` / `get_or_try_init_async`; the async variant exists specifically because some initialisation futures were large enough to overflow the Windows stack. — [cli/factory.rs#L269-300](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/factory.rs#L269-L300) [cli/factory.rs#L302-332](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/factory.rs#L302-L332)
- `deno task` exposes a shell-command registry: implementing `deno_task_shell::ShellCommand` and registering it (as `NpmCommand`, `NpxCommand`, `NodeCommand`, `NodeGypCommand`, `DenoCommand` do) intercepts that binary name inside task scripts. — [cli/task_runner.rs#L306-470](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/task_runner.rs#L306-L470) [cli/task_runner.rs#L178-230](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/task_runner.rs#L178-L230)
- The module loader exposes a JS-facing hook system: `ops::module_hooks::{op_module_hooks_register, op_module_hooks_poll_load, op_module_hooks_respond_load, op_module_default_resolve}` back a `LoaderHookRegistry` that `CliModuleLoader::load` consults before the graph, supporting Node-style `nextLoad(newUrl)` delegation. — [ext/node/lib.rs#L206-210](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/ext/node/lib.rs#L206-L210) [cli/module_loader.rs#L1445-1520](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/module_loader.rs#L1445-L1520) [runtime/shared.rs#L110-120](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/runtime/shared.rs#L110-L120)
- Alternative module sources plug in at `CliModuleLoaderFactory` construction: an `EszipModuleLoader` (from `eszip_module_loader_provider`) short-circuits `load()` entirely, which is how `deno run --eszip` works. — [cli/factory.rs#L1256-1282](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/factory.rs#L1256-L1282) [cli/module_loader.rs#L2224-2290](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/module_loader.rs#L2224-L2290) [cli/lib.rs#L326-334](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L326-L334)
- CLI-only ops live in `cli/ops/` (`bench.rs`, `deploy.rs`, `jupyter.rs`, `lint.rs`, `testing.rs`) and are injected per-subcommand via the `custom_extensions: Vec<Extension>` parameter of `create_custom_worker` — the deploy path passes `ops::deploy::deno_deploy::init()`. — [cli/ops/mod.rs](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/ops/mod.rs) [cli/worker.rs#L596-610](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/worker.rs#L596-L610) [cli/tools/deploy.rs#L85-95](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/deploy.rs#L85-L95)
- The developer CLI is itself a registry: `buildCommands(root)` in `tools/x.ts` returns a `Record<string, Command>` where each entry supplies `description`, a long `help` string explicitly written for LLM consumption, and an async `fn`; `cargoTestCommand` is a factory for the five test commands. — [tools/x.ts#L27-62](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/x.ts#L27-L62) [tools/x.ts#L102-395](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/x.ts#L102-L395)
- Agent workflows plug in via `.claude/skills/`: six skills (`fmt`, `lint-all`, `lint-js`, `node-compat`, `issue-triage`, `review-pr`) each declare frontmatter with `allowed-tools` — e.g. `review-pr` is scoped to `Bash(gh *) Bash(git *) Read Glob Grep Agent`. — [.claude/skills/review-pr/SKILL.md#L1-10](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/.claude/skills/review-pr/SKILL.md#L1-L10) [.claude/skills/fmt/SKILL.md](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/.claude/skills/fmt/SKILL.md)
- New CI jobs are added by editing the TypeScript generators (`.github/workflows/ci.ts` etc.) and regenerating; `job()`, `step()`, `defineMatrix()` and condition helpers like `hasPrLabel("ci-full")` compose the workflow, and lint fails if the `.generated.yml` is stale. — [.github/workflows/ci.ts#L33-100](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/.github/workflows/ci.ts#L33-L100) [.github/workflows/ci.ts#L270-360](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/.github/workflows/ci.ts#L270-L360) [tools/lint.js#L38](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/lint.js#L38)
- New integration coverage is added by dropping a directory with `__test__.jsonc` into `tests/specs/` — no Rust registration needed, since collection is directory-driven; `schema.json` documents the available keys (`args`, `output`, `envs`, `cwd`, `exitCode`, `flaky`, `if`, `tempDir`, `variants`, `repeat`, `timeout`). — [tests/specs/mod.rs#L290-305](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/specs/mod.rs#L290-L305) [tests/specs/schema.json#L1-70](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/specs/schema.json#L1-L70) [tests/specs/mod.rs#L44-110](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/specs/mod.rs#L44-L110)
- Lint rules can be added as JS plugins: `tools/lint_plugins/` is hashed into the unit-test CI hash because `lint_plugin_prefer_primordials_test` imports from it, and the runtime exposes `40_lint_selector.js`/`40_lint.js` to support plugin authoring. — [tests/unit/mod.rs#L24-27](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/unit/mod.rs#L24-L27) [cli/worker.rs#L682-691](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/worker.rs#L682-L691) [tools/lint_plugins](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/lint_plugins)
- The permission descriptor layer is pluggable at the container level: `RuntimePermissionDescriptorParser` is constructed once in `CliFactory::permission_desc_parser` and handed to every `PermissionsContainer`, so descriptor semantics are swappable without touching op sites. — [cli/factory.rs#L1136-1143](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/factory.rs#L1136-L1143) [runtime/permissions/runtime_descriptor_parser.rs](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/runtime/permissions/runtime_descriptor_parser.rs)

## Contributor handoff

Read `CLAUDE.md`, `tools/x.ts`, `cli/lib.rs`, and `cli/factory.rs` first — those four give you the command surface, the dispatch table, and the service graph. Use `./x` rather than raw cargo: `./x check` for fast feedback, `./x build` for a binary, `./x test-spec <filter>` for integration tests (a filter is mandatory and the runner will panic without one under Claude Code), and `./x verify` (fmt + lint-js) before committing. The repo's conventions are enforced mechanically: dprint formatting, a copyright-header check, generated-workflow freshness, and a clippy `disallowed_methods` list that is why you see `#[allow(clippy::disallowed_methods, reason = "…")]` sprinkled through startup code. Keep diffs minimal and avoid drive-by changes — the CLAUDE.md git workflow says so explicitly, and PRs are squash-merged so never force-push.
- Read first, in order: `CLAUDE.md` (build/test/PR conventions), `tools/x.ts` (the command registry with long help strings), `cli/lib.rs` (`main()` at :863 and `run_subcommand` at :124), `cli/factory.rs` (`CliFactoryServices` at :302), and `runtime/worker.rs` (`common_extensions` at :1199). — [CLAUDE.md](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/CLAUDE.md) [tools/x.ts#L102-395](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/x.ts#L102-L395) [cli/lib.rs#L124-556](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L124-L556) [cli/factory.rs#L302-345](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/factory.rs#L302-L345) [runtime/worker.rs#L1199-1262](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/runtime/worker.rs#L1199-L1262)
- Never run the full spec suite: `tests/specs/mod.rs::main` panics when `CLAUDE_CODE_ENTRYPOINT` is set without a filter — always use `./x test-spec <filter>` or `./x test-spec --list`. — [tests/specs/mod.rs#L266-279](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/specs/mod.rs#L266-L279) [tools/x.ts#L235-270](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/x.ts#L235-L270)
- Pre-commit is `./x fmt` then `./x lint-js` (bundled as `./x verify`) for JS/TS-only changes; if Rust changed, also run `./x lint` (includes clippy) and `./x check`. — [tools/x.ts#L370-395](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/x.ts#L370-L395) [CLAUDE.md](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/CLAUDE.md)
- Unit tests must go through cargo, not the built binary: `./x test-unit <filter>` runs `cargo test -p unit_tests --test unit -- <filter>`; `CLAUDE.md` explicitly warns against `./target/debug/deno test` for `tests/unit/`. — [tools/x.ts#L160-190](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/x.ts#L160-L190) [tests/unit/Cargo.toml](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/unit/Cargo.toml) [CLAUDE.md](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/CLAUDE.md)
- Formatting is dprint-driven with a repo config; do not hand-format. `tools/format.js` runs `npm:dprint@0.47.2 fmt --config .dprint.json`, and `--check` mode is available for verification. — [tools/format.js#L1-22](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/format.js#L1-L22) [.dprint.json](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/.dprint.json)
- Every source file needs the copyright header `// Copyright 2018-2026 the Deno authors. MIT license.` — `checkCopyright()` runs as part of `tools/lint.js` whenever both JS and Rust linting are enabled. — [tools/lint.js#L18-44](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/lint.js#L18-L44) [tools/copyright_checker.js](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/copyright_checker.js) [cli/lib.rs#L1](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1)
- Clippy enforces a disallowed-methods/types list per crate via `clippy.toml` files (present in `cli/`, `runtime/`, `ext/*`, `libs/*`); bypassing one requires an `#[allow(clippy::disallowed_methods, reason = "...")]` with a written reason, as seen around `std::env::current_dir` and `std::env::var_os` in startup. — [cli/clippy.toml](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/clippy.toml) [cli/lib.rs#L919-923](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L919-L923) [cli/lib.rs#L846-852](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L846-L852) [tools/lint.js#L31](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/lint.js#L31)
- Safe edit boundary for new native APIs: add ops inside the relevant `ext/<name>` crate, keep the `common_extensions` position stable, and remember the snapshot files (`runtime/snapshot.rs`, `runtime/snapshot_info.rs`, `runtime/web_worker.rs`) must stay in sync. — [runtime/worker.rs#L1206-1212](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/runtime/worker.rs#L1206-L1212) [runtime/snapshot.rs#L59-100](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/runtime/snapshot.rs#L59-L100)
- Anything in `.github/workflows/*.generated.yml` is build output — edit the `.ts` sibling and regenerate, or `ensureWorkflowYmlsUpToDate()` in `tools/lint.js` will fail CI. — [.github/workflows/ci.ts#L1-40](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/.github/workflows/ci.ts#L1-L40) [tools/lint.js#L38](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/lint.js#L38)
- Trap: adding a thread earlier in `main()` breaks the safety argument for the startup `env::set_var` calls; the node-shim setup, tunnel init, and `DENO_CONNECTED` assignment all carry comments stating they must run before any thread spawns. — [cli/lib.rs#L1023-1062](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1023-L1062) [cli/node_compat_shim.rs#L173-180](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/node_compat_shim.rs#L173-L180)
- Trap: large futures overflow the stack on Windows debug builds. `spawn_subcommand` uses `boxed_local()`, several subcommands add explicit `.boxed_local()`, and `Deferred::get_or_try_init_async` documents boxing for the same reason — preserve these when refactoring. — [cli/lib.rs#L108-122](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L108-L122) [cli/factory.rs#L280-290](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/factory.rs#L280-L290) [cli/tools/run/mod.rs#L179-181](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/tools/run/mod.rs#L179-L181)
- Git workflow per `CLAUDE.md`: branch off `main`, never force-push to a PR (commits are squashed on merge so incremental commits help reviewers), and keep changes scoped — no drive-by fixes in an unrelated PR. — [CLAUDE.md](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/CLAUDE.md)
- PR titles must match `type(scope): description` with types `feat|fix|perf|refactor|chore|docs|test|revert|BREAKING`; `tools/verify_pr_title.js` and the `review-pr` skill both gate on it. — [.claude/skills/review-pr/SKILL.md#L33-44](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/.claude/skills/review-pr/SKILL.md#L33-L44) [tools/verify_pr_title.js](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/verify_pr_title.js)
- Debugging aids that already exist: `DENO_STARTUP_PHASES=1` for boot-phase timings, `DENO_LOG=debug` for module-level logging, and `DENO_AUDIT_PERMISSIONS=<file|otel>` to record every permission access. — [cli/lib.rs#L841-860](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L841-L860) [cli/lib.rs#L1100-1130](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/cli/lib.rs#L1100-L1130) [CLAUDE.md](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/CLAUDE.md)
- When touching Node compatibility, use the repo's own workflow: `./x test-compat <filter>` runs `cargo test --test node_compat`, and `.claude/skills/node-compat/SKILL.md` documents the fix/skip/ignore decision procedure. — [tools/x.ts#L215-235](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tools/x.ts#L215-L235) [.claude/skills/node-compat/SKILL.md](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/.claude/skills/node-compat/SKILL.md) [tests/node_compat/config.jsonc](https://github.com/denoland/deno/blob/461f32ec6174d88b7e43654a054d46d67ae2fdab/tests/node_compat/config.jsonc)

Source repository: https://github.com/denoland/deno
Full evidence corpus: https://github.com/Codevetter/codevetter/tree/main/benchmarks/repo-unpacks/deno.json

## Public product links

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