This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
pnpm run build # Build the plugin
pnpm run watch # Build with watch mode
pnpm run lint # ESLint with auto-fix
pnpm run typecheck # TypeScript type checking
pnpm run test # Run all tests (vitest)
pnpm run validate # Run typecheck + lint + test
pnpm vitest run packages/backend/src/checks/<check-name>/index.spec.ts # Run a single test file
pnpm vitest run --coverage # Run tests with code coverage report
pnpm vitest run --coverage packages/backend/src/checks/<check-name>/index.spec.ts # Coverage for a specific checkThis is a Caido vulnerability scanner plugin organized as a pnpm monorepo with four packages:
packages/shared— Published as@caido-community/scanneron NPM. Type-only contract:API,Events,Spec, plus all public types (Session,UserConfig,Finding,Severity,ScanConfig,CheckMetadata, ...). Self-contained, zero workspace deps. Built withtsdownvia thepreparescript. Backend, frontend, and external CI/CD clients all consumeSpec.packages/engine— Core scanning engine. Defines the check execution model (step-based), runtime helpers (defineCheck,defineCheckV2,runCheck,createRegistry,createScheduler,keyStrategy,createMockRequest,createMockResponse). Imports its public types fromsharedand re-exports them for backwards compatibility with existing checks.packages/backend— Backend plugin. Contains 40+ vulnerability checks insrc/checks/. RPC handlers live insrc/api/{checks,config,queue,scanner}.tsand delegate to services insrc/services/. The SDK is set once viasetSDK(sdk)insrc/sdk.ts; services pull it viarequireSDK(). Hooks into Caido SDK events (intercepted responses for passive scanning,sdk.requests.send()for active scanning).packages/frontend— Vue 3 + Pinia + PrimeVue + TailwindCSS frontend. Depends onsharedonly — never onbackendorengine. Registers a sidebar page at/scannerand a keyboard shortcut (Ctrl+Shift+S) for active scanning.
The frontend↔backend contract is Spec = DefinePluginPackageSpec<{ manifestId: "scanner"; api: API; events: Events }> from packages/shared/src/index.ts. Backend uses SDK<Spec>, frontend uses Caido<Spec>. Plugin configuration lives in caido.config.ts. The plugin is built using @caido-community/dev.
- Add the method signature to
packages/shared/src/api.ts(noSDKfirst param — args only). - Implement the service in
packages/backend/src/services/<domain>.ts. CallrequireSDK()if you need the SDK; never accept it as a parameter. - Add the wrapper in
packages/backend/src/api/<domain>.ts((_sdk: SDK, ...args) => service(...args)) and re-export fromsrc/api/index.ts. - Register it in
packages/backend/src/index.tsviasdk.api.register("methodName", api.apiMethodName). - Add a unit test in
packages/backend/src/api/<domain>.test.tsthat mocks the relevant store and asserts the result.
Checks use a step-based execution model. Each check defines metadata, an initial state, a when condition, a dedupeKey, and one or more steps. Steps either done() or continueWith() to the next step.
Two APIs exist: defineCheck (step-based with explicit state machine) and defineCheckV2 (simplified, single execute function with ctx.parameters(), ctx.send(), ctx.finding()). Study existing checks in packages/backend/src/checks/ before writing new ones.
- Create
packages/backend/src/checks/<check-name>/index.tsandindex.spec.ts - Register in
packages/backend/src/checks/index.ts - Add to presets in
packages/backend/src/stores/presets/(Light, Balanced, BugBounty, Heavy)
Use runCheck from engine. Two distinct scenarios:
- Check doesn't run (
whenreturns false) → execution history is[] - Check runs but finds nothing → execution history is non-empty with empty findings
Test both positive cases (vulnerability detected) and negative cases (safe input).
- TypeScript only. Use
type, notinterface. Never useany. - Use
undefinedovernull. - No comments in generated code.
- Explicit nullish checks:
if (str !== undefined)notif (!str)— the linter enforces this for nullable strings. - Naming: folders are camelCase, component folders are PascalCase, files are camelCase.
- Declare variables close to usage, not at the top of functions.
- No alias types — rename and fix all occurrences instead.
- Vue 3 with
<script setup lang="ts">. Use PrimeVue components. - Props/emits: inline type definitions in
defineProps<>anddefineEmits<>(no separate type). - Destructure props with
toRefs. - Styling: TailwindCSS only. Dark mode default.
bg-surface-800for app background,bg-surface-700for cards. Prefer...-surface-...color classes. - Conditional classes: prefer
:class="{ ... }"Vue syntax.
Stores use the setup API with this file structure:
index.ts— public store combining composables, always exposesreset()useState.ts— private state usingdefinePrivateStore, contains theStatetypeuse[Feature].ts— composables with business logic, return getters/setters (never expose refs directly)use[Feature].spec.ts— tests
Store IDs follow the format stores.[feature-name].
Focus on behavior, not implementation. When a test fails, determine if it's a check issue or a test issue — fix the check if it has bugs, don't adjust tests to pass broken behavior.