This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Sage (Safety for Agents) — a lightweight Agent Detection & Response (ADR) layer for AI agents that guards commands, files, and web requests. Supports Claude Code, Cursor, and OpenClaw. See doc/spec.md for the full specification.
pnpm install # Install all dependencies
pnpm test # Run all tests (builds automatically, E2E excluded)
pnpm test -- --reporter=verbose # Verbose test output
pnpm test -- packages/core/src/__tests__/extractors.test.ts # Single test file
pnpm test -- -t "test name" # Run single test by name
pnpm test:e2e # All E2E tests (Claude Code + OpenClaw + Cursor + VS Code)
pnpm test:e2e:claude # Claude Code E2E only
pnpm test:e2e:openclaw # OpenClaw E2E only (requires gateway + token)
pnpm test:e2e:cursor # Cursor extension E2E only
pnpm test:e2e:vscode # VS Code extension E2E only
pnpm build # Build all packages (tsc + esbuild bundle)
pnpm build:sea # Build standalone SEA binaries (requires official Node.js, not Homebrew)
pnpm lint # Lint with Biome
pnpm lint:fix # Lint + auto-fix
pnpm check # Type check all packages
pnpm changeset # Create a changeset for your changes
pnpm run version # Apply changesets: bump versions, generate changelogs, sync manifests
bash scripts/pre-release-audit.sh # Pre-release content audit (requires .gitleaks.toml symlink)TypeScript monorepo with five packages:
packages/core/—@gendigital/sage-core: Platform-agnostic detection engine (extractors, heuristics, URL check client, decision engine, caching)packages/claude-code/—@gendigital/sage-claude-code: Claude Code hook entry points (pre-tool-use, session-start)packages/openclaw/—@gendigital/sage-openclaw: OpenClaw plugin connector (in-process hook, native approval).resources/is gitignored — generated bypnpm buildviasync-assets.mjs.packages/opencode/—@gendigital/sage-opencode: OpenCode plugin connectorpackages/extension/—sage-cursor: Cursor and VS Code extensionsthreats/— YAML threat definitions (data, not code).dummy.yamlcontains harmless canary rules for E2E testing (excluded from distribution bysync-assetsfilters)allowlists/— Trusted domain allowlistshooks/—hooks.jsonregistering hooks with Claude Code
| Tier | Scope | Files | Requires |
|---|---|---|---|
| 1 — Unit | Core library functions | packages/core/src/__tests__/*.test.ts |
pnpm dev deps |
| 2 — Integration | Hook/plugin entry points | packages/claude-code/src/__tests__/, packages/openclaw/src/__tests__/e2e-integration.test.ts |
pnpm dev deps |
| 3 — E2E (Claude Code) | Full plugin in Claude CLI | packages/claude-code/src/__tests__/e2e.test.ts |
claude CLI + ANTHROPIC_API_KEY |
| 3 — E2E (OpenClaw) | Full plugin in OpenClaw gateway | packages/openclaw/src/__tests__/e2e.test.ts |
OpenClaw gateway (token read from ~/.openclaw/openclaw.json) |
| 3 — E2E (Cursor extension) | Sage extension in Cursor Extension Host | packages/extension/src/__tests__/e2e.test.ts |
Installed Cursor executable |
| 3 — E2E (VS Code extension) | Sage extension in VS Code Extension Host | packages/extension/src/__tests__/e2e.test.ts |
Installed VS Code executable |
pnpm test runs tiers 1–2 automatically (builds via globalSetup before running). Tier 3 (E2E) is excluded — run with pnpm test:e2e (all), pnpm test:e2e:claude, pnpm test:e2e:openclaw, pnpm test:e2e:cursor, or pnpm test:e2e:vscode.
Claude Code E2E prerequisites: claude CLI in PATH, valid ANTHROPIC_API_KEY, and Sage must not be installed via the Claude Code marketplace (duplicate-plugin conflict with --plugin-dir).
OpenClaw E2E prerequisites: Running OpenClaw gateway with Sage installed. Auth token is read from ~/.openclaw/openclaw.json automatically (override via OPENCLAW_GATEWAY_TOKEN env var). See docs/development.md for gateway setup.
Cursor / VS Code E2E prerequisites: Installed Cursor / VS Code executables. Cursor headless agent coverage in pnpm test:e2e:cursor additionally requires the agent CLI (PATH or SAGE_AGENT_PATH) plus valid auth (agent login or CURSOR_API_KEY); if unavailable, only that headless sub-suite is skipped. Optional executable overrides: SAGE_CURSOR_PATH, SAGE_AGENT_PATH, SAGE_VSCODE_PATH, VSCODE_EXECUTABLE_PATH.
This is a multi-platform plugin with three connectors and a shared core:
-
Claude Code Connector (
packages/claude-code/src/) —pre-tool-use.tsreads tool call JSON from stdin, orchestrates core, outputs verdict JSON to stdout.session-start.tsscans installed plugins for threats. Both are bundled by esbuild into single CJS files. -
OpenClaw Connector (
packages/openclaw/src/) — In-process plugin usingapi.on('before_tool_call'). Flagged actions use OpenClaw's nativerequireApprovalmechanism with anonResolutioncallback that persists allowlist entries. Bundled into a single CJS file. -
Core Library (
packages/core/src/) — Platform-agnostic TypeScript library:extractors.ts— Extracts URLs, commands, file paths from tool inputsthreat-loader.ts— Loads YAML threat definitions fromthreats/heuristics.ts— Matches extracted artifacts against threat patternsclients/url-check.ts— HTTP client for URL reputation checking and endpoint resolverengine.ts— Decision engine combining signals into a Verdictcache.ts— JSON file verdict cache with TTLsallowlist.ts— User allowlist managementtrusted-domains.ts— Trusted domain loading and matchingaudit-log.ts— JSONL audit log for verdictsinstallation-id.ts— Persistent installation UUID (~/.sage/installation-id)version-check.ts— Version check via POST with environment contextsession-start.ts— Session start orchestrator (scan + version check)plugin-scanner.ts— Plugin file scanning for threatsplugin-scan-cache.ts— Plugin scan result cache
-
Plugin Config —
hooks/hooks.jsonregisters hooks,.claude-plugin/plugin.jsonis the plugin manifest,skills/security-awareness/SKILL.mdprovides security knowledge to Claude.
Data flow (Claude Code): Hook stdin → extract artifacts → check allowlist → check cache → heuristics + URL check → DecisionEngine → cache result → audit log → hook stdout JSON
Data flow (OpenClaw): before_tool_call event → extract artifacts → check allowlist → check cache → heuristics + URL check → DecisionEngine → cache result → audit log → block/pass
- Never skip git hooks. Do not use
--no-verifyongit commitorgit push. The hooks run gitleaks, lint, build, typecheck, and tests. If a hook fails, fix the underlying issue. - All detection patterns are data (YAML in
threats/), not hardcoded - Fail-open: every internal error path returns an allow verdict; extension hooks always exit with code
0 - Verdicts use three decisions:
allow,deny,askwith confidence scoring - Sensitivity presets: paranoid (0.70), balanced (0.85), relaxed (0.95)
- Merge precedence when multiple signals fire:
deny > ask > allow - URL check works without API key for basic malware/phishing detection
- Standalone binary via Node.js SEA for distribution (no runtime deps)
- Naming: YAML/JSON data uses
snake_case(threat_id,source_file); TypeScript interfaces usecamelCase(threatId,sourceFile). Conversion functions bridge the two at serialization boundaries.
Before creating a pull request, run the @"code-simplifier:code-simplifier (agent)" subagent on all changed files to review for clarity, consistency, and maintainability improvements. Apply any suggested changes before opening the PR.