Skip to main content

LSP server + VS Code extension

Vulkro ships a Language Server Protocol server, exposed as the vulkro lsp subcommand of the main binary, and a VS Code extension that consumes it. The same .vsix loads in Cursor and Windsurf (both VS Code forks). The extension builds in two editions from one codebase: the core edition (driven by vulkro) and a Salesforce edition (driven by vulkro-sf).

The extension surfaces Vulkro findings inside your editor as diagnostics, with hover-to-explain, quick-fix code actions, report export, a CI-parity check, and optional AI assistance. AI assistance is advisory and local: it never changes a deterministic scan result, and the published benchmark is AI-free.

Install

Distribution status: the extension is built and distributed as a .vsix today. A Visual Studio Marketplace listing is coming soon.

The extension spawns the vulkro binary you already have, so install the scanner first (see the install guide). Build the .vsix from integrations/editors/vscode:

cd integrations/editors/vscode
npm install
npm run package:editions

That emits vulkro-<version>.vsix (core) and vulkro-sf-<version>.vsix (Salesforce edition). Install one through your editor: Extensions view, ... menu, Install from VSIX.

If the binary cannot be found when the extension starts, it offers an Install action (also the Vulkro: Install or update the scanner binary command) that downloads the right release for your platform, verifies its .sha256, and installs it into ~/.vulkro/bin. That download runs only when you trigger it, never on activation; it respects VULKRO_OFFLINE=1 and honours the VULKRO_CDN host override.

What you get

  • Diagnostics on open and save. Open any Python, JavaScript, TypeScript, JSX/TSX, Go, or Java file inside a project with a root marker (.git, package.json, pyproject.toml, Cargo.toml, go.mod, pom.xml, build.gradle, build.gradle.kts, composer.json, sfdx-project.json, or vulkro.toml). The server paints the open file first with a fast single-file scan, then reconciles with a full project scan moments later. Saving re-runs the engine; typing only republishes cached results (debounced), so keystrokes never trigger a re-scan.
  • Free scanning without an account. JavaScript, TypeScript, Python, and Go, plus IaC, containers, secrets, and dependency manifests, scan without signing in. Signing in unlocks the licensed languages (for example Java, and Salesforce Apex through the Salesforce server); the first sign-in on a device starts a 14-day trial of the full product. Licenses are issued directly by our team ([email protected]).
  • Salesforce projects additionally start a second vulkro-sf lsp server for Apex, Aura, LWC, Visualforce, Flow, and metadata. See the Salesforce extension page for the SFDX specifics.
  • Hover to explain. Hovering a diagnostic surfaces the rule id, severity, message, and remediation in a Markdown popup.
  • Quick fixes on the lightbulb. Every Vulkro diagnostic offers Suppress (insert a // vulkro:disable next-line <rule> comment) and Explain (the rule's long-form explainer). A small set of clear-cut patterns (weak hash, yaml.load, cookie flags, debug flags, and similar) also gets a deterministic one-line fix; each template refuses to edit any line whose shape it does not fully recognise. Fix with AI (review) appears when local AI is set up (see below).
  • Sidebar views. The Vulkro activity-bar container shows Overview, This File, Issues, and Account by default. Turning on vulkro.showAdvancedViews reveals Changes, History, Impact, Codemap, Trends, Dependencies, AI Hunt, Suppressions, and Ask Vulkro. A status bar item shows the live finding count.
  • Watch mode. vulkro.watch (or Vulkro: Toggle watch mode) rescans the whole workspace as files change on disk, including files you have not opened and changes made by git checkout or codegen. Off by default.
  • Baseline. Set, clear, or toggle a baseline to hide known findings and surface only new ones.
  • Severity display floor. vulkro.severityThreshold hides findings below the chosen level from the gutter, the Problems panel, and the Vulkro views. It is a display floor, not a scan setting: the scanner still detects everything.

You stay in control of edits

The language server never writes to your files. Every edit it can produce (the suppression comment, a deterministic one-line fix, an AI fix candidate) is proposed through the editor and applied only when you accept it. AI fix candidates go one step further: a candidate is only offered after a fresh deterministic re-scan of the patched working copy confirms the finding no longer appears and the file still parses. That is what "verified" means here; it does not claim the build compiles or the tests pass.

Export a report

Vulkro: Export report (SARIF and other formats) (vulkro.exportReport) runs the same whole-project vulkro scan that CI would, captures the output, and saves it where you choose:

  • SARIF 2.1.0 (the portable default): open it in a SARIF viewer or upload it to your code-scanning platform.
  • JSON: the native Vulkro findings document, for scripts and jq.
  • HTML is offered only when the installed engine's scan accepts --format html; the command probes scan -h so the picker never offers a format your binary would reject.

A scan that exits 0 (clean) or 1 (findings reported) both produce a report; only exit 2 (error) is treated as a failure.

Editor / CI parity

Vulkro: Verify editor / CI parity (vulkro.verifyCiParity) runs the CI-equivalent scan (vulkro scan <root> --format json), counts findings by severity, and reports how your vulkro.severityThreshold display floor maps onto a CI invocation. It then offers to copy the matching command, for example:

vulkro scan . --min-severity low

--min-severity is the CLI twin of the editor's display floor: it drops findings below the level from the output (composing with --fail-on, which then evaluates the filtered set), so CI and the editor agree on what appears. See CLI: scan.

AI assistance (local first)

All AI features are optional and advisory: they never change a deterministic scan result, and the benchmark stays AI-free. The default transport is a local model through Ollama, default model qwen2.5-coder:7b, so nothing leaves your machine.

  • Vulkro: Set up AI model lists recommended models (with their licenses), pulls your pick, and self-tests the connection. Test AI connection and Disable AI manage it afterwards.
  • Fix issue with AI (review + apply) and Fix all issues with AI draft fixes for findings, validate each one with a deterministic re-scan (a fix is verified when the re-scan no longer reports the finding and the file still parses; the build compiling or tests passing is not claimed), show you the diff, and apply only what you accept.
  • Explain impact with AI, Review my changes with AI, AI Hunt, and the Ask Vulkro chat view build on the same local model.

Using your editor's AI model instead

If you do not run Ollama, vulkro.ai.transport: "editor" (or Vulkro: Use editor AI model) reuses the model your editor already provides (for example GitHub Copilot) through a loopback shim on 127.0.0.1. This is opt-in behind an explicit confirmation, because prompt content (which can include your source code and findings) is sent to whatever provider backs that model, usually a cloud service. It is refused outright when VULKRO_OFFLINE=1 is set. Vulkro: Use local AI model switches back.

Your editor's AI agent can call Vulkro

On hosts new enough to expose the APIs (the extension targets VS Code 1.101+; older hosts degrade gracefully), the extension also plugs the scanner into the editor's own AI agent:

  • Language-model tools. vulkro_scan_file scans a single file and returns its findings; vulkro_explain_finding explains a rule id. Agent mode can call both, and you can reference them in prompts (#vulkroScanFile, #vulkroExplainFinding). The Salesforce edition registers vulkro_sf_* twins, so both editions co-exist in one host.
  • MCP server. An MCP server-definition provider teaches the editor to launch the engine's own stdio MCP server (vulkro mcp serve) with VULKRO_OFFLINE=1 set, so the agent's MCP scans never reach the network.

Settings

SettingDefaultPurpose
vulkro.pathvulkroPath to the vulkro binary, or the bare name if it is on PATH. The extension spawns <path> lsp.
vulkro.severityThresholdlowLowest severity shown (critical, high, medium, low, info). A display floor: match it to your CI --min-severity.
vulkro.showAdvancedViewsfalseReveal the full set of sidebar views beyond Overview, This File, Issues, and Account.
vulkro.watchfalseRescan the whole workspace as files change on disk, including unopened files.
vulkro.lsp.debounceMs300Debounce window (ms) for didChange republishes, clamped to [50, 5000]. Passed as VULKRO_LSP_DEBOUNCE_MS.
vulkro.ai.model(empty)Override the local AI model; empty uses the engine default (qwen2.5-coder:7b). Passed as VULKRO_AI_MODEL.
vulkro.ai.url(empty)Base URL of the local Ollama (OpenAI-compatible) endpoint; empty uses http://127.0.0.1:11434/v1. Passed as VULKRO_AI_URL.
vulkro.ai.transportlocallocal keeps AI fully on-machine; editor reuses the editor's model through the loopback shim (opt-in, see above).
vulkro.trace.serveroffTrace LSP traffic in the Vulkro output channel.

The Salesforce server has its own namespace (vulkro-sf.path, vulkro-sf.severityThreshold, vulkro-sf.scanOnSave, vulkro-sf.watch, vulkro-sf.targetOrg, vulkro-sf.trace.server); see the Salesforce extension page.

Because the server maps Critical and High to the same editor severity (Error), the critical and high thresholds behave identically in the editor.

How the LSP talks to the scanner

vulkro lsp runs the scan in-process: no subprocess, no JSON-over-pipe. It uses the same detection pipeline as vulkro scan (the full extractor set, the auth model, taint analysis, and the same suppression pass), so a // vulkro:disable directive silences the same finding in the editor and in CI. Diagnostics are pushed by the server per file. vulkro lsp exits 0 on a clean shutdown and 2 on an operational error; set VULKRO_LSP_LOG=1 for a stderr message trace.

Performance

Opening the first file in a project (and every save) publishes the current file's findings from a fast single-file scan first, so squiggles land in a fraction of a second, then a full project scan reconciles the complete picture. Typing republishes cached results only; the engine re-runs on save (or on any disk change when watch mode is on).

For a scoped terminal loop alongside the editor, run something like vulkro scan . --min-confidence high --scope src (see CLI: scan).

Suppressing network egress from inside the editor

To suppress all network egress from the binary the editor spawns, set:

// settings.json
"terminal.integrated.env.osx": {
"VULKRO_OFFLINE": "1"
}

(Adapt osx to linux / windows as needed.)

VULKRO_OFFLINE=1 is the single switch and covers everything: scans, the managed binary install, and the editor-AI transport (which is refused under it). The MCP server the extension registers is always launched with VULKRO_OFFLINE=1 regardless.

What this isn't (yet)

  • No Marketplace listing yet. The .vsix is the distribution channel today; the Marketplace listing is coming soon.
  • No standalone JetBrains plugin. The server works with any LSP-aware editor in principle; vulkro lsp --help prints ready-made snippets for Neovim (nvim-lspconfig), Helix, and Emacs eglot. VS Code (and its forks) is the only editor with a packaged extension today.
  • No unreviewed rewrites. Every edit, deterministic or AI-drafted, is applied only when you accept it, and AI candidates must first pass the deterministic re-scan described above.
  • No as-you-type engine runs. Diagnostics refresh from cache while you type; the engine re-runs on save (or on disk changes in watch mode).
  • vulkro scan: the CLI front door that produces the same findings the LSP surfaces, plus the --min-severity parity flag.
  • Salesforce extension page: the SFDX side, driven by the vulkro-sf server.