RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Configs/CLAUDE.md/oven-sh/bun

CLAUDE.md

src/CLAUDE.md
CLAUDE.md

Quality

76/100

Scores the file, not the repository.

Length

1,774 words

17 headings · 17 code blocks

Repository

95k

— · pushed 0 days ago

Last changed

3 days ago

First indexed 3 days ago.
oven-sh/bun/src/CLAUDE.mdRawGitHub
1## Rust
2 
3`src/` is a Cargo workspace (rooted at the repo's top-level `Cargo.toml`, ~200
4member crates). The runtime is built as `libbun_rust.a` via `cargo build -p
5bun_bin` (driven by `scripts/build/rust.ts`). Key crates:
6 
7- `bun_core` (`src/bun_core/`) — strings, formatting, logging, env vars, allocator/heap helpers, the foundation everything else uses
8- `bun_sys` (`src/sys/`) — cross-platform syscall wrappers (`File`, `Fd`, `Dir`, `Error`)
9- `bun_paths` (`src/paths/`) — path joining/normalization, the path-buffer pool
10- `bun_jsc` (`src/jsc/`) — JSC value types, `Strong`/`Weak`, FFI imports, `URL`
11- `bun_runtime` (`src/runtime/`) — JS-visible APIs (server, fetch, node compat, crypto)
12- `bun_js_parser`, `bun_js_printer`, `bun_resolver`, `bun_bundler`, `bun_install`, `bun_collections`, `bun_threading`, `bun_alloc` — the rest of the pipeline
13- `bun_bin` (`src/bun_bin/`) — the staticlib root that `cargo build` links
14 
15Conventions:
16 
17- `cargo check -p <crate>` for fast iteration; `bun bd` builds and links everything.
18- Don't `.unwrap()` a fallible path that user input or the OS can hit at runtime — return the error. `.unwrap()` is for invariants you can prove.
19- The C ABI / syscall boundary uses `bun_sys::Maybe<T>` (= `Result<T, bun_sys::Error>`); ordinary Rust code uses `Result<T, E>` with `?`.
20- Each crate defines its own `Error` enum (a `thiserror::Error` at `<crate>/error.rs`, re-exported as `crate::Error` + `crate::Result`). Errno codes nest via `Sys(#[from] bun_errno::SystemErrno)`; OOM via `Alloc(#[from] bun_alloc::AllocError)`. `bun_sys::Error` is the rich syscall error (errno + syscall tag + path); `From<bun_sys::Error> for bun_errno::SystemErrno` exists for `?`-chaining.
21- NEVER add comments to deleted code blocks.
22- Do not add comments that reference context from the transcript.
23- Avoid adding comments where not necessary.
24 
25## Prefer `bun_core` / `bun_sys` over `std`
26 
27The `std` equivalents either lose OS error info, allocate where we have pools,
28or don't match the cross-platform behavior the runtime needs.
29 
30| Instead of | Use |
31| --------------------------------------- | ------------------------------------------------------------------------------------ |
32| `std::fs::File` | `bun_sys::File` (owns the fd; closes on `Drop`) |
33| `std::fs::read` / `write` | `bun_sys::File::read_from` / `File::create` + `write_all` |
34| `std::path::Path::join` | `bun_paths::resolve_path::join` / `join_string_buf` |
35| `std::path::Path::parent`/`file_name` | `bun_paths::dirname` / `bun_paths::basename` |
36| `std::env::var` | `bun_core::env_var::*::get()` (typed + cached) |
37| `String::from_utf8` for JS-visible strs | `bun_core::String::clone_utf8` / `borrow_utf8` |
38| `&str` operations on byte slices | `bun_core::strings::*` (SIMD-backed `&[u8]` ops) |
39| `eprintln!` for debug logging | `bun_core::declare_scope!` + `scoped_log!` |
40| `std::process::Command` | `bun_core::util::spawn_sync_inherit` (CLI helpers) or `bun_spawn_sys` (full control) |
41| `Box::new` + raw ptr round-trip | `bun_core::heap::{into_raw, take, destroy}` |
42 
43## `bun_sys` — System Calls (`src/sys/`)
44 
45Syscall wrappers preserve errno via `Maybe<T> = Result<T, bun_sys::Error>`.
46 
47```rust
48use bun_sys::{File, Fd, O};
49 
50let file = File::openat(Fd::cwd(), b"path/to/file", O::RDONLY, 0)?;
51let mut buf = vec![0u8; 4096];
52let n = file.read_all(&mut buf)?; // loops until EOF or full
53// `file` closes on Drop.
54```
55 
56Key types and functions:
57 
58- `Fd` (`bun_core::Fd`, re-exported) — cross-platform file descriptor. `Fd::cwd()`, `Fd::stdin()/stdout()/stderr()`, `fd.close()`.
59- `File::open(path: &ZStr, flags, mode)` / `File::openat(dir: Fd, path: &[u8], flags, mode)` / `File::make_open(...)` (creates parent dirs) / `File::create(dir, path, truncate)`
60- `file.read(buf)` / `read_all(buf)` / `read_to_end()` / `read_to_end_small()` / `write(buf)` / `write_all(buf)`
61- `bun_sys::open`, `read`, `write`, `pread`, `pwrite`, `stat`, `fstat`, `lstat`, `mkdir`, `unlink`, `rename`, `symlink`, `chmod` — free fns over `Fd`
62- Open flags: `bun_sys::O::RDONLY`, `O::WRONLY | O::CREAT | O::TRUNC`, etc.
63 
64`bun_sys::Error` carries `errno`, `syscall: Tag`, `path: Box<[u8]>`. Convert
65to a JS exception via `bun_sys_jsc::ErrorJsc::to_js`:
66 
67```rust
68use bun_sys_jsc::ErrorJsc;
69match File::openat(Fd::cwd(), path, O::RDONLY, 0) {
70 Ok(f) => f,
71 Err(err) => return Ok(err.to_js(global)?),
72}
73// Internally: err.to_system_error().to_error_instance(global)
74```
75 
76## Strings (`bun_core::String` and `bun_core::strings`)
77 
78`bun_core::String` is the FFI-compatible 5-variant tagged union shared with C++
79(`BunString` in `BunString.cpp`). It bridges Rust and JSC and can hold a
80`WTFStringImpl` (Latin-1 or UTF-16). **Latin-1 is NOT UTF-8** — bytes 128–255
81are single chars in Latin-1 but invalid UTF-8 — so converting either direction
82requires a real encoder, not a cast.
83 
84```rust
85use bun_core::String;
86 
87let s = String::clone_utf8(utf8_bytes); // copies into a WTFStringImpl
88let s = String::borrow_utf8(utf8_bytes); // no copy; caller keeps slice alive
89let s = String::static_(b"literal"); // 'static slice, never freed
90 
91let utf8: ZigStringSlice = s.to_utf8(); // ref-holding view; falls back to allocating a copy
92let owned: Vec<u8> = s.to_utf8_bytes();
93```
94 
95To/from JS values, use the `bun_jsc::StringJsc` extension trait:
96 
97```rust
98use bun_jsc::StringJsc;
99let js: JSValue = s.to_js(global)?;
100let s = bun_core::String::from_js(value, global)?;
101let err = s.to_error_instance(global);
102```
103 
104`bun_core::strings` is the SIMD-backed `&[u8]` toolkit. Use it instead of
105`std::str` / `std::iter` for searching and comparing byte slices:
106 
107```rust
108use bun_core::strings;
109 
110strings::index_of(haystack, needle) // Option<usize>
111strings::contains(haystack, needle) // bool
112strings::eql(a, b) // bool
113strings::starts_with(s, prefix) // bool
114strings::ends_with(s, suffix) // bool
115strings::has_prefix_comptime(s, b"x") // 'static comparand
116strings::has_suffix_comptime(s, b"x")
117strings::first_non_ascii(s) // Option<u32>
118strings::to_utf16_alloc(...) // encoding conversions
119```
120 
121## Paths (`bun_paths`)
122 
123Path helpers operate on `&[u8]` and are platform-parameterized via the
124`Platform` const-generic (`Posix`, `Windows`, `Loose`, `Nt`; `platform::Auto`
125picks the host). Never use `std::path` for runtime path logic.
126 
127```rust
128use bun_paths::{dirname, basename};
129use bun_paths::resolve_path::{self, platform};
130 
131let dir = dirname(path); // Option<&[u8]>
132let name = basename(path); // &[u8]
133let joined = resolve_path::join::<platform::Auto>(&[a, b]); // &'static [u8] (threadlocal buf)
134let joined = resolve_path::join_string_buf::<platform::Auto>(&mut buf, &[a, b]); // caller buf
135let rel = resolve_path::relative(from, to);
136```
137 
138Use the path-buffer pool to avoid 64 KB stack allocations on Windows
139(`PathBuffer` is `[u8; PATH_MAX_BYTES]`, ~64 KB on Windows):
140 
141```rust
142use bun_paths::path_buffer_pool;
143 
144let mut buf = path_buffer_pool::get(); // PoolGuard<PathBuffer>, returns to pool on Drop
145let joined = resolve_path::join_string_buf::<platform::Auto>(&mut *buf, &[a, b]);
146```
147 
148`bun_paths::os_path_buffer_pool` selects the wide (`u16`) variant on Windows
149and the narrow (`u8`) variant on POSIX.
150 
151## URL Parsing (`bun_jsc::URL`)
152 
153WHATWG-compliant, backed by WebKit's URL parser. Returns `None` for invalid input.
154 
155```rust
156use bun_jsc::URL;
157 
158let url = URL::from_utf8(href)?; // Option<NonNull<URL>>
159// caller owns the C++ object — destroy it when done:
160// unsafe { URL::destroy(url.as_ptr()) }
161 
162url.protocol() // bun_core::String
163url.pathname() // bun_core::String
164url.host() // bun_core::String — the hostname WITHOUT the port (opposite of JS `host`!)
165url.port() // u32 (u32::MAX = unset; otherwise u16 range)
166```
167 
168`URL::href_from_js`, `URL::file_url_from_string`, `URL::path_from_file_url`
169do whole-string conversions. The JSC-free shim `bun_url::whatwg::URL` exposes
170`hostname()`, which returns the host WITH the port (also the opposite of JS
171`hostname`) — so `bun_jsc::URL::host` and `bun_url::whatwg::URL::hostname`
172are effectively swapped relative to their JS namesakes.
173 
174## MIME Types (`bun_http_types::MimeType`)
175 
176```rust
177use bun_http_types::{MimeType, mime_type};
178 
179let mime = mime_type::by_extension(b"html"); // MimeType
180let mime = mime_type::by_extension_no_default(b"xyz"); // Option<MimeType>
181 
182mime.category // Category::Javascript | Css | Html | Json | Image | Text | Wasm | ...
183mime.category.is_text_like()
184```
185 
186Common constants: `JAVASCRIPT`, `JSON`, `HTML`, `CSS`, `TEXT`, `WASM`, `ICO`, `OTHER`.
187 
188## Memory & Allocators
189 
190The `#[global_allocator]` is mimalloc (or `std::alloc::System` under
191`cfg(bun_asan)`), so plain `Box`/`Vec`/`String` already use it. When pairing
192with C/C++ that may free the bytes, route through `bun_alloc::default_alloc`
193rather than `mi_*` directly — under ASAN the global allocator is libc's, so a
194`mi_free`/`mi_usable_size` on `Box`-owned memory is an allocator mismatch.
195 
196OOM handling: do not let a runtime OOM unwind into FFI. Use
197`bun_core::handle_oom` (or the `.unwrap_or_oom()` extension) to convert
198`Result<T, AllocError>` into a controlled crash:
199 
200```rust
201use bun_core::{handle_oom, UnwrapOrOom};
202let buf = handle_oom(allocator.alloc(size));
203let v = vec.try_reserve(n).unwrap_or_oom();
204```
205 
206Heap round-trips that need to cross FFI use `bun_core::heap`:
207 
208```rust
209use bun_core::heap;
210let raw: *mut T = heap::into_raw(Box::new(value)); // hand ownership to C
211let boxed: Box<T> = unsafe { heap::take(raw) }; // reclaim ownership
212unsafe { heap::destroy(raw) }; // reclaim + drop in one step
213```
214 
215**Arena gotcha:** values allocated in `bun_alloc::MimallocArena` (the AST
216allocator and similar) do **not** run `Drop` when the arena resets — the
217backing pages are bulk-freed. If a type owns a heap allocation, refcount, or
218fd, free it explicitly before the arena resets. Don't rely on `Drop` for
219correctness in arena-backed code.
220 
221## Environment Variables (`bun_core::env_var`)
222 
223Typed, cached accessors. Each known env var is a module with a `get()`
224returning the right type (`Option<...>` if no default).
225 
226```rust
227use bun_core::env_var;
228 
229env_var::HOME::get() // Option<&[u8]>
230env_var::CI::get() // bool (has default)
231env_var::BUN_CONFIG_DNS_TIME_TO_LIVE_SECONDS::get() // u64 (has default)
232```
233 
234## Logging (`bun_core::output`)
235 
236Scoped debug logging. Declare a scope once per module; gate with
237`BUN_DEBUG_<SCOPE>=1` at runtime; the body dead-strips in release builds.
238 
239```rust
240bun_core::declare_scope!(my_feature, hidden); // hidden: opt-in via BUN_DEBUG_my_feature=1
241// or `visible` to log by default in debug builds
242 
243bun_core::scoped_log!(my_feature, "processing {} items", count);
244```
245 
246User-facing colored output (auto-detects TTY, strips ANSI when piped):
247 
248```rust
249bun_core::pretty!("<green>success<r>: {}\n", msg);
250bun_core::prettyln!("done");
251bun_core::pretty_errorln!("<red>error<r>: {}", msg);
252```
253 
254## Spawning Subprocesses
255 
256For simple inherit-stdio CLI helpers:
257 
258```rust
259use bun_core::util::spawn_sync_inherit;
260let status = spawn_sync_inherit(&[b"git", b"status"])?;
261```
262 
263For full control (pipes, custom env, posix_spawn flags) use `bun_spawn_sys`
264(`src/spawn_sys/`). The runtime `Bun.spawn` implementation lives in
265`src/runtime/api/bun/{spawn.rs, process.rs, subprocess.rs}` — look there for
266the JS-facing path.
267 
268## JSC Interop & FFI Safety
269 
270These are the patterns that trip people up. Get them wrong and you get
271crashes that only reproduce under load or in CI.
272 
273### Pointer provenance at FFI boundaries
274 
275If a callback may free `self` (close, error, GC finalize), do **not**
276materialize `&self`/`&mut self` at the boundary — a `&self`-derived raw
277pointer carries `SharedReadOnly` provenance, and `Box::from_raw`/dealloc
278through it is UB. Pass and dispatch off `*mut Self` until the body proves
279ownership. `src/io/PipeWriter.rs`'s `impl_streaming_writer_parent!` macro
280encodes the three modes:
281 
282- `borrow = mut` — body forms `&mut *this`; safe when nothing re-enters
283- `borrow = shared` — body forms `&*this`; safe when re-entrant code only needs `&Self`
284- `borrow = ptr` — body calls `Self::method(this, ..)` with `this: *mut Self`; required when the callback may free `self`
285 
286### `Strong` / `Weak` JS handles
287 
288`bun_jsc::Strong` keeps a JS value alive; it is `!Send`/`!Sync` and must be
289created and dropped on the JS thread.
290 
291```rust
292use bun_jsc::Strong;
293let strong = Strong::create(value, global);
294let v: JSValue = strong.get();
295// drop(strong) releases the GC handle
296```
297 
298`bun_jsc::Weak<T>` is the GC-cleared variant. For raw values without a `Strong`
299wrapper, `JSValue::protect()` / `unprotect()` and `ensure_still_alive()` are
300available, but `Strong` is preferred — it can't be forgotten or unbalanced.
301 
302### Refcount transfer on `to_js()` / `create()`
303 
304A `to_js()` / `create()` that returns a wrapped pointer **transfers** the
305caller's `+1` to the JS wrapper. Do not `ref()` again before the return; the
306finalizer derefs once. The leak-or-UAF symptoms of getting this wrong are
307distinctive: an extra `ref()` leaks until process exit; a missing `ref()` on a
308non-transferring path UAFs at GC.
309 
310### Cross-thread string hazards
311 
312`AtomString`s live in a per-thread table. Never deref one from another thread —
313it trips `wasRemoved` in `AtomStringImpl::remove()`. If a `bun_core::String`
314may be dropped from a non-JS thread (HTTP worker, threadpool, dying VM), build
315it via `String::clone_utf8` (a plain `WTFStringImpl` with an atomic refcount),
316not from an interned/atomized JS string. See the comment in
317`src/runtime/webcore/fetch/FetchTasklet.rs` near `Response::init` for the
318canonical example of this bug class and its fix.
319 
320## Common Patterns
321 
322```rust
323// Read a file, return JS error on failure
324let contents = match bun_sys::File::openat(Fd::cwd(), path, O::RDONLY, 0)
325 .and_then(|f| f.read_to_end())
326{
327 Ok(bytes) => bytes,
328 Err(err) => return Ok(err.to_js(global)?),
329};
330 
331// Heap-allocated FFI handle with explicit lifecycle
332let raw = bun_core::heap::into_raw(Box::new(MyHandle::new()));
333register_with_c(raw);
334// ... later, in the matching teardown callback:
335unsafe { bun_core::heap::destroy(raw) };
336 
337// Hashing
338bun_wyhash::hash(bytes) // u64
339bun_wyhash::hash_with_seed(seed, bytes)
340```
341 

Commands it names

  • cargo build
  • cargo check -p <crate>
  • bun bd

Sections

  • Rust
  • Prefer `bun_core` / `bun_sys` over `std`
  • `bun_sys` — System Calls (`src/sys/`)
  • Strings (`bun_core::String` and `bun_core::strings`)
  • Paths (`bun_paths`)
  • URL Parsing (`bun_jsc::URL`)
  • MIME Types (`bun_http_types::MimeType`)
  • Memory & Allocators
  • Environment Variables (`bun_core::env_var`)
  • Logging (`bun_core::output`)
  • Spawning Subprocesses
  • JSC Interop & FFI Safety
  • Pointer provenance at FFI boundaries
  • `Strong` / `Weak` JS handles
  • Refcount transfer on `to_js()` / `create()`
  • Cross-thread string hazards
  • Common Patterns

What it covers

setupbuildcode-styletypesperformancedo-not

Stack — with the evidence

typescript

(1.00)

javascript

(1.00)

rust

(1.00)

node

(1.00)

bun

(1.00)

react

(1.00)

nextjs

(0.70)

express

(0.70)

drizzle

(0.70)

postgres

(0.70)

tailwind

(0.70)

vitest

(0.70)

jest

(0.70)

biome

(0.70)

prisma

(0.60)

github-actions

(0.60)

Format

CLAUDE.md

Claude Code's memory file. Shaped like AGENTS.md but with two things it lacks: @path imports, so shared rules live in one place, and a user-scope layer that follows the developer across repos rather than shipping with the code.

What the corpus says about it

Repository

Owner
oven-sh
Language
—
License
—
Archived
no

All configs in this repo

Also in oven-sh/bun

Diff this repo’s formats

One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?

The other instruction files in this repository
RepositoryFormatStackCoversScoreChanged
oven-sh/bun.github/workflows/CLAUDE.md · 95kCLAUDE.mdtypescriptjavascript+14testlint-formatarchgit+281/100today
oven-sh/bunCLAUDE.md · 95kCLAUDE.mdtypescriptjavascript+14buildteststylearch+396/1003 days ago
oven-sh/bunscripts/verify-baseline-static/CLAUDE.md · 95kCLAUDE.mdtypescriptjavascript+14buildtesting-strategy65/1003 days ago
oven-sh/bunsrc/js/CLAUDE.md · 95kCLAUDE.mdtypescriptjavascript+14buildarchdo-not85/1003 days ago
oven-sh/bunsrc/jsc/bindings/v8/AGENTS.md · 95kAGENTS.mdtypescriptjavascript+14buildtestarchtesting-strategy+481/1003 days ago
oven-sh/bunsrc/jsc/bindings/v8/CLAUDE.md · 95kCLAUDE.mdtypescriptjavascript+14buildtestarchtesting-strategy+481/1003 days ago
oven-sh/buntest/CLAUDE.md · 95kCLAUDE.mdtypescriptjavascript+14teststyletesting-strategydo-not97/1003 days ago
oven-sh/buntest/js/node/test/parallel/CLAUDE.md · 95kCLAUDE.mdtypescriptjavascript+14test43/1003 days ago
Diff against .github/workflows/CLAUDE.md Diff against CLAUDE.md Diff against scripts/verify-baseline-static/CLAUDE.md Diff against src/js/CLAUDE.md Diff against src/jsc/bindings/v8/AGENTS.md Diff against src/jsc/bindings/v8/CLAUDE.md Diff against test/CLAUDE.md Diff against test/js/node/test/parallel/CLAUDE.md

Similar configs

Same format, overlapping stack, ranked by quality.

Same format, overlapping stack, ranked by quality
RepositoryFormatStackCoversScoreChanged
bagisto/bagistoCLAUDE.md · 28kCLAUDE.mdphplaravel+8setupbuildteststyle+5100/1003 days ago
livewire/livewireCLAUDE.md · 24kCLAUDE.mdphpvitest+4setupbuildteststyle+4100/1003 days ago
microsoft/playwrightCLAUDE.md · 94kCLAUDE.mdtypescriptjavascript+10buildtestlint-formatstyle+7100/1003 days ago
dotCMS/corecore-web/CLAUDE.md · 949CLAUDE.mdjavanode+13teststylearchtesting-strategy+3100/1003 days ago
nimbalyst/nimbalystpackages/android/CLAUDE.md · 1.4kCLAUDE.mdtypescriptnode+16setupbuildstylearch+2100/1003 days ago
filamentphp/filamentCLAUDE.md · 32kCLAUDE.mdphplaravel+5buildtestlint-formatstyle+7100/1003 days ago
Adit-Jain-srm/NightmareNetCLAUDE.md · 45CLAUDE.mdtypescriptpython+18buildtestlint-formatstyle+6100/1003 days ago
dotCMS/coreCLAUDE.md · 949CLAUDE.mdjavanode+9setupbuildteststyle+799/100today
RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack