MANDATORY: Act as principal-level engineer. Follow these guidelines exactly.
NEVER use rm -rf with glob patterns matching hidden files
- FORBIDDEN FOREVER:
rm -rf * .*- Deletes .git directory, destroys repository - Safe alternatives:
git clean -fdx, explicit directories (rm -rf build/ node_modules/), orfind . -mindepth 1 -maxdepth 1 ! -name '.git' -exec rm -rf {} +
- Before ANY structural refactor on a file >300 LOC: remove dead code, unused exports, unused imports first — commit that cleanup separately before the real work
- Multi-file changes: break into phases (≤5 files each), verify each phase before the next
- When pointed to existing code as a reference: study it before building — working code is a better spec than any description
- Work from raw error data, not theories — if a bug report has no error output, ask for it
- On "yes", "do it", or "go": execute immediately, no plan recap
Before claiming any task is complete:
- Run the actual command — execute the script, run the test, check the output
- State what you verified, not just "looks good"
- FORBIDDEN: Claiming "Done" when output shows failures, or characterizing incomplete/broken work as complete
- Re-read every file modified; confirm nothing references something that no longer exists
- After 10+ messages: re-read any file before editing it — do not trust remembered contents
- Read files >500 LOC in chunks using offset/limit; never assume one read captured the whole file
- Before every edit: re-read the file. After every edit: re-read to confirm the change applied correctly
- When renaming anything, search separately for: direct calls, type references, string literals, dynamic imports, re-exports, test files — one grep is not enough
- Tool results over 50K characters are silently truncated — if search returns suspiciously few results, narrow scope and re-run
- For tasks touching >5 files: use sub-agents with worktree isolation to prevent context decay
- Before calling anything done: present two views — what a perfectionist would reject vs. what a pragmatist would ship
- After fixing a bug: explain why it happened
- If a fix doesn't work after two attempts: stop, re-read the relevant section top-down, state where the mental model was wrong, propose something fundamentally different
- If asked to "step back" or "going in circles": drop everything, rethink from scratch
- If the user's request is based on a misconception, say so before executing
- If you spot a bug adjacent to what was asked, flag it: "I also noticed X — want me to fix it?"
- Do not add features, refactor, or make improvements beyond what was asked
- Try the simplest approach first; flag architectural issues and wait for approval before restructuring
- When asked to "make a plan," output only the plan — no code until given the go-ahead
- NEVER claim done with something 80% complete — finish 100% before reporting
- When a multi-step change doesn't immediately show gains, commit and keep iterating — don't revert
- After EVERY code change: build, test, verify, commit. This is a single atomic unit
- Reverting is a last resort after exhausting forward fixes — and requires explicit user approval
- Fix ALL issues when asked - Never dismiss as "pre-existing" or "not caused by my changes"
- When asked to fix, lint, or check: fix everything found, regardless of who introduced it
NEVER create documentation files unless explicitly requested
- FORBIDDEN: Creating README.md, GUIDE.md, HOWTO.md, ARCHITECTURE.md, or docs/ directories
- Only exceptions: Package README.md (1-2 sentences), CLAUDE.md, .claude/ directory
NO BACKWARD COMPATIBILITY - FORBIDDEN to maintain. Actively remove when encountered. No deprecation paths, no re-exports, no _var renames. Just delete unused code.
- 🚨 NEVER use
npx,pnpm dlx, oryarn dlx— usepnpm exec <package>for devDep binaries, orpnpm run <script>for package.json scripts - HTTP Requests: NEVER use
fetch()— usehttpJson/httpText/httpRequestfrom@socketsecurity/lib/http-request
Conventional Commits: <type>(<scope>): <description>. NO AI attribution (commit-msg hook auto-strips it).
- Default to NO comments. Only when the WHY is non-obvious to a senior engineer
- NEVER use
nullexcept for__proto__: nullor external API requirements; useundefined - ALWAYS use
{ __proto__: null, ... }for config/return/internal-state objects - NEVER use dynamic imports (
await import()) - Prefer
Promise.allSettledoverPromise.allfor independent operations - ALWAYS use
eslint-disable-next-lineabove the line, NEVER trailingeslint-disable-line - ALWAYS use Edit tool for code modifications, NEVER sed/awk
NEVER change shell: WIN32 to shell: true — shell: WIN32 enables shell on Windows (needed) and disables on Unix (not needed). If spawn fails with ENOENT, separate command from arguments.
- Cherry-pick
fs(import { existsSync, promises as fs } from 'node:fs'), default importpath/os/url/crypto - Use
@socketsecurity/lib/spawninstead ofnode:child_process(except inadditions/) - Exception: cherry-pick
fileURLToPathfromnode:url
ALWAYS use fileURLToPath(import.meta.url) === path.resolve(process.argv[1]) — works cross-platform. NEVER use endsWith() or raw URL comparison.
ALWAYS pass libc parameter for Linux platform operations. Prefer getCurrentPlatformArch() which auto-detects libc. Missing libc causes builds to output to wrong directories.
ALWAYS use @socketsecurity/lib/logger instead of console.*. NEVER add emoji/symbols manually (logger provides them). Exception: additions/ directory.
Code embedded into Node.js during early bootstrap. Special constraints:
- No third-party packages — only built-in modules
- Use
require('fs')notrequire('node:fs')—node:protocol unavailable at bootstrap - NEVER import from
@socketsecurity/*packages - ALWAYS start
.jsfiles with'use strict';
All node:smol-* modules REQUIRE the node: prefix (enforced via schemelessBlockList in lib/internal/bootstrap/realm.js).
Available: node:smol-http, node:smol-https, node:smol-purl, node:smol-versions, node:smol-manifest, node:smol-ilp, node:smol-sql, node:smol-vfs
ALWAYS use primordials for Map/Set operations in internal modules: SafeMap, SafeSet, MapPrototypeGet/Set/Delete/Has, SetPrototypeAdd/Delete/Has, ArrayFrom, ObjectKeys. Use *Ctor suffix for constructors shadowing globals (BigIntCtor, ErrorCtor). .size is safe on SafeMap/SafeSet.
ALWAYS use ObjectKeys() + indexed for-loop (faster than for...in with hasOwnProperty).
- NEVER use C++ exceptions — Node.js compiled with
-fno-exceptions. Use status flags. - ALWAYS use full
socketsecurity/...include paths (e.g.,#include "socketsecurity/http/http_fast_response.h") env-inl.hvsenv.h: includeenv-inl.hif .cc file usesEnvironment*methods
- Use flat
.jsfiles (Node.js upstream convention), NEVER directories withindex.js internalBindingis already in scope — NEVER require it from'internal/bootstrap/realm'
- Node.js:
packages/node-smol-builder/patches/source-patched/*.patch - iocraft:
packages/iocraft-builder/patches/*.patch
ALWAYS use standard unified diff (--- a/, +++ b/). NEVER use git format-patch output.
Required headers:
# @node-versions: vX.Y.Z (or @iocraft-versions: vX.Y.Z)
# @description: One-line summary
#
--- a/file
+++ b/file- Each patch affects ONE file and does NOT depend on other patches
- Minimal touch, clean diffs, no style changes outside scope
- To regenerate: use
/regenerating-patchesskill - Manual:
diff -u a/file b/file, add headers, validate withpatch --dry-run
/security-scan— AgentShield + zizmor security audit/quality-scan— comprehensive code quality analysis/quality-loop— scan and fix iteratively- Agents:
code-reviewer,security-reviewer,refactor-cleaner(in.claude/agents/) - Shared subskills in
.claude/skills/_shared/
- ALWAYS use
pnpm run build, NEVER invoke Makefiles directly (build scripts handle dependency downloads) - ALWAYS run clean before rebuilding:
pnpm --filter <pkg> clean && pnpm --filter <pkg> build - NEVER manually delete checkpoint files — the clean script knows all locations
Source packages (binject, bin-infra, build-infra) are canonical. ALL work in source packages, then sync to additions/. NEVER make changes only in additions/ — they will be overwritten.
When modifying source, bump .github/cache-versions.json for all dependents:
| Changed | Bump |
|---|---|
| build-infra/src/socketsecurity/build-infra/ | stubs, binflate, binject, binpress, node-smol |
| bin-infra/src/socketsecurity/bin-infra/ | stubs, binflate, binject, binpress, node-smol |
| binject/src/socketsecurity/binject/ | binject, node-smol |
| stubs-builder/src/ | stubs, binpress, node-smol |
| binpress/src/ | binpress, node-smol |
| binflate/src/ | binflate |
NEVER write source-code-scanning tests. Write functional tests that verify behavior. For modules requiring the built binary: use integration tests with final binary (getLatestFinalBinary), NEVER intermediate stages.
ALWAYS use npm registry directly (npm pack or https://registry.npmjs.org/), NEVER CDNs like unpkg.
- Mach-O: macOS/iOS, ELF: Linux, PE: Windows
- Checkpoint: Cached snapshot of build progress for incremental builds
- Cache Version: Version in
.github/cache-versions.jsonthat invalidates CI caches - Upstream: Original Node.js source before patches
- SEA: Single Executable Application (standalone with runtime + app code)
- VFS: Virtual File System embedded inside a binary
- Additions Directory: Code embedded into Node.js during build
- Binary Injection: Inserting data into compiled binary without recompilation
- Section/Segment: Named regions in executables
- LIEF: Library for reading/modifying executable formats
- LZFSE: Apple's compression (fast decompression, good ratio)
- UPX: Classic executable packer
- Stub Binary: Small executable that decompresses and runs main binary
- musl: Lightweight C library for Alpine Linux (vs glibc on most distros)
- Universal Binary: macOS binary with ARM64 + x64 code
- binject: Injects data into binaries (SEA resources, VFS archives)
- binpress: Compresses binaries (LZFSE/UPX)
- binflate: Decompresses binaries
- stubs-builder: Builds self-extracting stub binaries
- node-smol-builder: Builds custom Node.js binary with Socket patches
Codex is for advice and critical assessment ONLY — never for making code changes. Proactively consult before complex optimizations (>30min estimated) to catch design flaws early.
See ../socket-registry/CLAUDE.md for testing, code style, and CI patterns.