π¨ MANDATORY: Act as principal-level engineer with deep expertise in TypeScript, Node.js, and SDK development.
- Identify users by git credentials: Extract name from git commit author, GitHub account, or context
- π¨ When identity is verified: ALWAYS use their actual name - NEVER use "the user" or "user"
- Direct communication: Use "you/your" when speaking directly to the verified user
- Discussing their work: Use their actual name when referencing their commits/contributions
- Example: If git shows "John-David Dalton jdalton@example.com", refer to them as "John-David"
- Other contributors: Use their actual names from commit history/context
- 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
MANDATORY: 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 any test output shows failures, or characterizing incomplete/broken work as complete
- If type-check or lint is configured, run it and fix ALL errors before reporting done
- 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
- 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
- Do not add features, refactor, or make improvements beyond what was asked
- Try the simplest approach first; if architecture is actually flawed, flag it and wait for approval before restructuring
- When asked to "make a plan," output only the plan β no code until given the go-ahead
- 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
- Before risky changes: offer to checkpoint β "want me to commit before this?"
- If a file is getting unwieldy (>400 LOC): flag it β "this is big enough to cause pain β want me to split it?"
Quick references:
- Commits: Conventional Commits
<type>(<scope>): <description>- NO AI attribution - Scripts: Prefer
pnpm run foo --flagoverfoo:barscripts - Docs: Use
docs/folder, lowercase-with-hyphens.md filenames, pithy writing with visuals - Dependencies: After
package.jsonedits, runpnpm installto updatepnpm-lock.yaml - Backward Compatibility: π¨ FORBIDDEN to maintain - actively remove when encountered (see canonical CLAUDE.md)
Terminal Symbols (based on @socketsecurity/lib/logger LOG_SYMBOLS):
- β Success/checkmark - MUST be green (NOT β )
- β Error/failure - MUST be red (NOT β)
- β Warning/caution - MUST be yellow (NOT
β οΈ ) - βΉ Info - MUST be blue (NOT βΉοΈ)
- β Step/progress - MUST be cyan (NOT β or βΆ)
Usage (use logger methods, NOT manual color application):
import { getDefaultLogger } from '@socketsecurity/lib/logger'
const logger = getDefaultLogger()
logger.success(msg) // Green β
logger.fail(msg) // Red β
logger.warn(msg) // Yellow β
logger.info(msg) // Blue βΉ
logger.step(msg) // Cyan βImportant:
- Always use logger methods for status symbols
- Never manually apply colors with yoctocolors-cjs or similar
- Logger automatically handles colored symbols
Allowed Emojis (use sparingly):
- π¦ Packages
- π‘ Ideas/tips
- π Launch/deploy/excitement
- π Major success/celebration
General Philosophy:
- Prefer colored text-based symbols (βββ βΉβ) for maximum terminal compatibility
- Always color-code symbols: green=success, red=error, yellow=warning, blue=info, cyan=step
- Use emojis sparingly for emphasis and delight
- Avoid emoji overload - less is more
- When in doubt, use plain text
Socket SDK for JavaScript/TypeScript - Programmatic access to Socket.dev security analysis
Core Structure:
- Entry:
src/index.ts - SDK Class:
src/socket-sdk-class.ts- All API methods - HTTP Client:
src/http-client.ts- Request/response handling - Types:
src/types.ts- TypeScript definitions - Utils:
src/utils.ts- Shared utilities - Constants:
src/constants.ts
Features: Full TypeScript support, API client, package analysis, security scanning, org/repo management, SBOM support, batch operations, file uploads
- Build:
pnpm build(production build) - Watch:
pnpm build --watch(dev mode with 68% faster incremental builds) - Test:
pnpm test - Type check:
pnpm run type - Lint:
pnpm run lint - Check all:
pnpm check - Coverage:
pnpm run cover
Development tip: Use pnpm build --watch for 68% faster rebuilds (9ms vs 27ms).
All configuration files are organized in .config/ directory for cleanliness:
| File | Purpose | When to Modify |
|---|---|---|
| tsconfig.json | Main TS config (extends tsconfig.base.json) | Rarely - only for project-wide TS changes |
| .config/tsconfig.base.json | Base TS settings (strict mode, targets) | Rarely - shared TS configuration |
| .config/tsconfig.check.json | Type checking for type command | Rarely - only for type-check configuration |
| .config/tsconfig.dts.json | Declaration file generation settings | Rarely - only for type output changes |
| .config/esbuild.config.mjs | Build orchestration (ESM output, node18+ target) | When adding new entry points or build steps |
| .oxlintrc.json | Linting rules (oxlint configuration) | When adding new lint rules |
| .oxfmtrc.json | Code formatting (oxfmt configuration) | When changing format rules |
| .config/vitest.config.mts | Main test config (default runner) | When changing test setup or plugins |
| .config/vitest.config.isolated.mts | Isolated test config (for vi.doMock() tests) | Never - only for isolated test mode |
| .config/vitest.coverage.config.mts | Shared coverage thresholds (β₯99%) | When adjusting coverage requirements |
| .config/isolated-tests.json | List of tests requiring isolation | When adding tests that use vi.doMock() |
| .config/taze.config.mts | Dependency update tool settings | When changing update policies |
Why multiple TypeScript configs?
tsconfig.json- Main config for building the SDKtsconfig.check.json- Type checking configuration for type commandtsconfig.dts.json- Declaration file generation has different output requirements
Why multiple Vitest configs?
vitest.config.mts- Standard test mode (default, fastest)vitest.config.isolated.mts- Process isolation for tests usingvi.doMock()(slower)vitest.coverage.config.mts- Shared coverage settings to avoid duplication
All logger.error() and logger.log() calls include empty string:
- β
logger.error(''),logger.log('') - β
logger.error(),logger.log()
Default to NO comments. Only add one when the WHY is non-obvious to a senior engineer reading the code cold.
- Extensions:
.mtsfor TypeScript modules - Module headers: π¨ MANDATORY
@fileoverviewheaders - "use strict": β FORBIDDEN in .mjs/.mts (ES modules are strict)
- Semicolons: Use semicolons (unlike other Socket projects)
- Type safety: β FORBIDDEN
any; useunknownor specific - Type imports: Always
import type - Nullish values: Prefer
undefinedovernull- useundefinedfor absent/missing values
- π¨ NEVER use
process.chdir()- use{ cwd }options and absolute paths instead- Breaks tests, worker threads, and causes race conditions
- Always pass
{ cwd: absolutePath }to spawn/exec/fs operations
Documentation organized alphabetically within functional categories
- Type properties: Required first, then optional; alphabetical within groups
- Class members: 1) Private properties, 2) Private methods, 3) Public methods (all alphabetical)
- Object properties: Alphabetical in literals (except semantic ordering)
- Destructuring: Alphabetical (
const { apiKey, baseUrl, timeout })
Vitest Configuration: Two configs available:
.config/vitest.config.mts- Main config (default).config/vitest.config.isolated.mts- Full process isolation for vi.doMock()
- Directories:
test/- Test files,test/utils/- Shared utilities - Naming: Descriptive names
- β
socket-sdk-upload-manifest.test.mts,describe('SocketSdk - Upload Manifest') - β
test1.test.mts,describe('tests')
- β
- Consolidated files:
socket-sdk-api-methods.coverage.test.mts- Comprehensive API method tests
setupTestClient(token?, options?) - Combined nock setup + client creation (RECOMMENDED)
import { setupTestClient } from './utils/environment.mts'
describe('My tests', () => {
const getClient = setupTestClient('test-api-token', { retries: 0 })
it('should work', async () => {
const client = getClient()
// ... test code
})
})setupTestEnvironment() - Just nock setup (for custom client creation)
import { setupTestEnvironment, createTestClient } from './utils/environment.mts'
describe('My tests', () => {
setupTestEnvironment()
it('should work', async () => {
const client = createTestClient('custom-token')
// ... test code
})
})createTestClient(token?, options?) - Just client creation (no nock setup)
const client = createTestClient('test-token', { retries: 0 })isCoverageMode - Flag for coverage detection
if (isCoverageMode) {
// Skip tests that don't work well in coverage mode
}- All tests:
pnpm test - Specific file:
pnpm test <file>(glob support) - Coverage:
pnpm run cover
- Use setupTestClient(): Combines nock setup and client creation in one call
- Use getClient() pattern: Access client instance returned by setupTestClient()
- Mock HTTP with nock: All HTTP requests must be mocked
- Auto cleanup: Nock mocks cleaned automatically in beforeEach/afterEach
- Test both paths: Success + error paths for all methods
- Cross-platform: Test path handling on Windows and Unix
- Follow patterns: See
test/unit/getapi-sendapi-methods.test.mtsfor examples
NEVER write source-code-scanning tests
Do not read source files and assert on their contents (.toContain('pattern')). These tests are brittle and break on any refactor.
- Write functional tests that verify behavior, not string patterns
- For modules requiring a built binary: use integration tests
- For pure logic: use unit tests with real function calls
- π¨ MANDATORY:
SocketDev/socket-registry/.github/workflows/ci.yml@<SHA>with full SHA - Format:
@662bbcab1b7533e24ba8e3446cffd8a7e5f7617e # main - Custom runner:
scripts/test.mjswith glob expansion - Memory: Auto heap size (CI: 8GB, local: 4GB)
π¨ MANDATORY: When creating changelog entries for version bumps:
- Check OpenAPI updates: Analyze
types/api.d.tschangesgit diff v{prev}..HEAD -- types/ - Document user-facing changes:
- New endpoints (e.g.,
/openapi.json) - Updated parameter descriptions/behavior
- New type categories/enum values (e.g., 'dual' threat type)
- Breaking changes to API contracts
- New endpoints (e.g.,
- Focus: User impact only, not internal infrastructure
- Rationale: OpenAPI changes directly impact SDK users
- CI vs Local: CI uses published npm packages, not local
- Package detection: Use
existsSync()notfs.access() - Test failures: Check unused nock mocks, ensure cleanup
- Windows compatibility important - test path handling
- Use utilities from @socketsecurity/registry where available
- Maintain consistency with surrounding code