MANDATORY: Act as principal-level engineer. Follow these guidelines exactly.
- Identify users by git credentials (commit author, GitHub account). Use their actual name, never "the user".
- Use "you/your" when speaking directly; use their name when discussing their work.
This repo may have multiple Claude sessions running concurrently against the same checkout, against parallel git worktrees, or against sibling clones. Several common git operations are hostile to that and silently destroy or hijack the other session's work.
-
FORBIDDEN in the primary checkout (the one another Claude may be editing):
git stash— shared stash store; another session canpopyours.git add -A/git add .— sweeps files belonging to other sessions.git checkout <branch>/git switch <branch>— yanks the working tree out from under another session.git reset --hardagainst a non-HEAD ref — discards another session's commits.
-
REQUIRED for branch work: spawn a worktree instead of switching branches in place. Each worktree has its own HEAD, so branch operations inside it are safe.
# From the primary checkout — does NOT touch the working tree here. git worktree add -b <task-branch> ../<repo>-<task> main cd ../<repo>-<task> # edit, commit, push from here; the primary checkout is untouched. cd - git worktree remove ../<repo>-<task>
-
REQUIRED for staging: surgical
git add <specific-file> [<file>…]with explicit paths. Never-A/.. -
If you need a quick WIP save: commit on a new branch from inside a worktree, not a stash.
The umbrella rule: never run a git command that mutates state belonging to a path other than the file you just edited.
MANDATORY: Review CLAUDE.md before any action. No exceptions.
- Before ANY structural refactor on a file >300 LOC: remove dead code/unused exports/imports first — commit separately
- Multi-file changes: break into phases (≤5 files each), verify each phase before the next
- Study existing code before building
- 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
- Run the actual command — execute, don't assume
- State what you verified, not just "looks good"
- FORBIDDEN: Claiming "Done" when any test output shows failures
- Run type-check/lint if configured; fix ALL errors before reporting done
- Re-read every modified file; confirm nothing references removed items
- After 10+ messages: re-read files before editing
- Read files >500 LOC in chunks (offset/limit)
- Before every edit: re-read. After every edit: re-read to confirm
- When renaming: search direct calls, type refs, string literals, dynamic imports, re-exports, tests
- Tool results over 50K chars are silently truncated — narrow scope and re-run if incomplete
- For tasks touching >5 files: use sub-agents with worktree isolation
- Never fix a display/rendering problem by duplicating state
- 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?"
- You are a collaborator, not just an executor
- Fix warnings when you find them (lint, type-check, build, runtime) — don't leave them for later
- Do not add features, refactor, or make improvements beyond what was asked
- Simplest approach first; flag architectural flaws and wait for approval
- When asked to "make a plan," output only the plan — no code until given the go-ahead
- Default to perfectionist mindset: when you have latitude to choose, pick the maximally correct option — no shortcuts, no cosmetic deferrals. Fix state that looks stale even if not load-bearing. If pragmatism is the right call, the user will ask for it explicitly. "Works now" ≠ "right."
- NEVER claim done at 80% — finish 100% before reporting
- Fix forward: if an approach fails, analyze why, adjust, rebuild — not
git checkout - After EVERY code change: build, test, verify, commit as a single atomic unit
- Reverting requires explicit user approval
- Before calling anything done: present both views — what a perfectionist would reject vs. what a pragmatist would ship — and let the user choose. If the user gives no signal, default to perfectionist: do the fuller fix.
- After fixing a bug: explain why it happened and what category of bug it represents
- If a fix fails twice: stop, re-read top-down, state where the mental model was wrong
- If asked to "step back": drop everything, rethink from scratch
- Offer to checkpoint before risky changes
- Flag files >400 LOC for potential splitting
- Fix ALL issues when asked — never dismiss as "pre-existing"
- Never create files unless necessary; always prefer editing existing files
- Forbidden to create docs unless requested
- 🚨 NEVER use
npx,pnpm dlx, oryarn dlx— usepnpm exec <package>orpnpm run <script>
If user repeats instruction 2+ times, ask: "Should I add this to CLAUDE.md?"
- Commits: Conventional Commits
<type>(<scope>): <description>— NO AI attribution - Scripts: Prefer
pnpm run foo --flagoverfoo:barvariants - Dependencies: After
package.jsonedits, runpnpm install - Backward Compatibility: 🚨 FORBIDDEN to maintain — actively remove when encountered
- Safe Deletion: Use
safeDelete()from@socketsecurity/lib/fs(NEVERfs.rm/rmSyncorrm -rf) - HTTP Requests: NEVER use
fetch()— usehttpJson/httpText/httpRequestfrom@socketsecurity/lib/http-request Promise.race/Promise.any: NEVER pass a long-lived promise (interrupt signal, pool member) into a race inside a loop. Each call re-attaches.thenhandlers to every arm; handlers accumulate on surviving promises until they settle. For concurrency limiters, use a single-waiter "slot available" signal (resolved by each task's.then) instead of re-racingexecuting[]. See nodejs/node#17469 and@watchable/unpromise. Race with two fresh arms (e.g. one-shotwithTimeout) is safe.- File existence: ALWAYS
existsSyncfromnode:fs. NEVERfs.access,fs.stat-for-existence, or an asyncfileExistswrapper. Import:import { existsSync, promises as fs } from 'node:fs'. - Stream discipline: stdout carries ONLY the data the command was asked to produce (JSON payload, report, fix output — the thing a script pipes into
jqor redirects to a file). stderr carries everything else: progress, spinners, status, warnings, errors, dry-run previews, context, banners, prompts. Test: wouldcommand | jqorcommand > filemake sense with only the stdout content? If no, it belongs on stderr. Under--json/--markdown, stdout MUST parse as the declared format with no prefix/suffix text.
Do NOT litter the repo with markdown. Allowed: docs/, root README.md/CHANGELOG.md/SECURITY.md/CLAUDE.md, packages/*/README.md, test/fixtures/*/README.md, test/*/README.md.
.claude/ exception: markdown under .claude/agents/, .claude/commands/, .claude/hooks/, .claude/skills/ is allowed (harness-loaded config). Ad-hoc analysis/session notes still disallowed.
- Build:
pnpm run build(smart) |--force|pnpm run build:cli|pnpm run build:sea - Test:
pnpm test(monorepo root) |pnpm --filter @socketsecurity/cli run test:unit <path> - Lint:
pnpm run lint| Type check:pnpm run type| Check all:pnpm run check - Fix:
pnpm run fix| Dev:pnpm dev(watch) | Run built:node packages/cli/dist/index.js <args>
- 🚨 NEVER use
--before test file paths — runs ALL tests - Always build before testing:
pnpm run build:cli - Update snapshots:
pnpm testu <path>or--updateflag - NEVER write source-code-scanning tests — verify behavior, not string patterns
Follow Keep a Changelog. User-facing only: Added, Changed, Fixed, Removed. Concise.
.mtsextensions for TS modules- 🚨 Separate
import typestatements — NEVER mix runtime and type imports - Process spawning: MUST use
spawnfrom@socketsecurity/registry/lib/spawn(NEVERchild_process) - Array destructuring:
{ 0: key, 1: data }instead of[key, data] - Dynamic imports: 🚨 FORBIDDEN — always static imports
- Sorting: 🚨 MANDATORY — lists, exports, destructured properties, doc headers alphabetically
- Comments: Default NO. Only when WHY is non-obvious. Own line, not inline.
- Functions: alphabetical; private first, exported second
- Object mappings:
__proto__: nullfor static lookup;Mapfor dynamic - Array length:
!array.lengthnot=== 0 - Catch:
catch (e)notcatch (error) - Numbers: underscore separators (
20_000); don't modify values inside strings - Flags: MUST use
MeowFlagstype with descriptive help - Error handling:
InputError/AuthErrorfromsrc/utils/errors.mts; preferCResult<T>; avoidprocess.exit(1) - GitHub API: Octokit from
src/utils/github.mts, not raw fetch
- Simple (<200 LOC, no subcommands): single
cmd-*.mts - Complex:
cmd-*.mts+handle-*.mts+output-*.mts+fetch-*.mts
Advice and critical assessment ONLY — never for making code changes. Consult before complex optimizations (>30min).
/security-scan— AgentShield + zizmor security audit/quality-scan— comprehensive code quality analysis/quality-loop— scan and fix iteratively/sync-checksums— sync external tool SHA-256 checksums- Agents:
code-reviewer,security-reviewer,refactor-cleaner(in.claude/agents/) - Shared subskills in
.claude/skills/_shared/