cursor — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited cursor (MCP Server) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
*Compiler-in-the-loop steering for coding agents - Cursor and Claude Code. LSPSteer runs your workspace's real language server on each edit, extracts the diagnostics scoped to the lines that changed and the in-scope type signatures needed to fix them*, and feeds that back to the coding agent - so generation is constrained by program analysis instead of corrected by post-hoc lint.
It plugs into both editors through the same warm daemon: an MCP tool (typecheck_scope) the agent calls after editing, plus optional hooks that enforce a clean type-check before the agent ends its turn. One command wires it up: lspsteer init.
An agent's edit can be perfectly well-formed and still wrong: it passes anumberwhere astringid is required, or reads.balanceoff aPromise<User>. Grammar- and syntax-level guidance never catches this. Studies of LLM compilation failures find the overwhelming majority are type-check errors, not syntax errors - so the dominant failure class is exactly the one a type checker sees and a linter doesn't.
Honest result up front: in a paired, deterministically-scored A/B (150 runs, eval/), compiler-in-the-loop feedback beats no feedback on first-attempt correctness, but on small readable repos LSPSteer matches an agent that just runs tsc itself. The edge it is designed for (scoping when tsc emits hundreds of errors, resolving types that are expensive to read) should show on large repos, which the current suite does not cover. Full numbers below and in eval/FINDINGS.md.
The core mechanism is the steering note: after an edit, LSPSteer returns the diagnostics scoped to the changed lines plus the in-scope type signatures, so the agent works from the resolved types instead of guessing them.
LSPSteer found 2 errors in your edit to payments.ts. Fix before finishing.
Errors:
- payments.ts:4:25 [error ts2345] Argument of type 'number' is not assignable
to parameter of type 'string'.
> const user = findUser(42);
- payments.ts:5:15 [error ts2339] Property 'balance' does not exist on type
'Promise<User>'.
> return user.balance * 1.1;
Relevant types in scope (use these to fix correctly):
- function chargeUser
- findUser: function findUser(id: string): Promise<User>The difference from "just run tsc": errors are scoped to the edit, and the agent is handed the resolved types it is actually working with (findUser(id: string): Promise<User>) rather than a wall of project-wide output.
<details> <summary>Illustrative full loop (<code>npm run demo</code>): broken edit, steered, fixed</summary>
This shows the steering note inside an end-to-end flow on the included fixture. It is an illustration of the mechanism, not a benchmark; for measured impact see the result line above.
STEP 1 - Agent writes payments.ts (compiles? no. syntactically valid? yes)
export function chargeUser(): number {
const user = findUser(42);
return user.balance * 1.1;
}
STEP 2 - LSPSteer analyzes the edit (cold: daemon boot + tsserver load)
[the steering note shown above]
STEP 3 - Re-analyze the same edit (warm: server already loaded, sub-second)
[same note, now in < 1s]
STEP 4 - Agent applies the guidance
export async function chargeUser(id: string): Promise<number> {
const user = await findUser(id);
return user.isActive ? 10 : 0;
}
LSPSteer: payments.ts is type-clean.</details>
A cold tsserver/Pyright/rust-analyzer load is several seconds; warm edits are sub-second. LSPSteer keeps language servers warm in a long-lived daemon, one per project, behind a Unix-socket IPC. The hooks and the MCP server are thin clients. Measured on the fixture:
| latency | |
|---|---|
| cold load (one-time per project) | ~5-12s |
| warm analysis (every edit after) | < 1s |
Two layers; the first is the robust default. Both work identically in Cursor and Claude Code - only the config file locations and the hook event names differ, and lspsteer init writes the right ones for you.
typecheck_scope MCPtool. A bundled rule (Cursor's .cursor/rules/lspsteer.mdc, or a block in CLAUDE.md for Claude Code) tells the agent to call it after editing a file and fix any reported errors before finishing. This rides stable, well-specified MCP I/O.
afterFileEdit,Claude Code PostToolUse on Edit|Write|MultiEdit) records edited files and pre-warms the server; a stop hook (Cursor stop, Claude Code Stop) re-checks them when the agent tries to end the turn and hands back a steering note if errors remain. The two harnesses expect different Stop-hook output shapes; LSPSteer detects which one it's running under and emits the right one ({"decision":"block","reason":…} for Claude Code), failing open on any error.
typecheck_scope(file, changedRanges?) - diagnostics scoped to the changedlines + in-scope type signatures. The steering tool.
get_diagnostics(file) - every diagnostic for a file (whole-file check).lspsteer_status(workspaceRoot?) - which servers are warm.LSPSteer is a TypeScript/Node project. From a clone:
npm install
npm run build
node dist/cli.js doctor . # verifies the language server resolves & startsThen wire it into any project with a single command:
# from inside the target project (writes config for both editors by default):
lspsteer init
# or pick one, and/or pass a target directory:
lspsteer init --cursor /path/to/project
lspsteer init --claude /path/to/projectinit writes the MCP registration, the rule, and the (optional) hooks with absolute paths filled in, merging into any existing config rather than overwriting it, and is safe to re-run (idempotent). It targets:
| Cursor | Claude Code | |
|---|---|---|
| MCP | .cursor/mcp.json | .mcp.json |
| Rule | .cursor/rules/lspsteer.mdc | block appended to CLAUDE.md |
| Hooks | .cursor/hooks.json | .claude/settings.json |
Reload your editor afterward. To wire it by hand instead, see cursor/README.md and claude/README.md.
lspsteer init [dir] Wire LSPSteer into a project (--cursor | --claude | --both)
lspsteer daemon [root] Run the warm-LSP daemon in the foreground
lspsteer mcp Run the MCP server on stdio (what the editor launches)
lspsteer doctor [root] Check that language servers resolve and start
lspsteer status [root] List warm language serversTypeScript/JavaScript works today (via typescript-language-server, which uses your project's own TypeScript). Support is pluggable: a language is one LanguageAdapter entry (how to launch the server + which files it owns). Python (Pyright) and Rust (rust-analyzer) adapters are stubbed in src/lsp/adapters.ts - install the server and the rest of the pipeline (diff-scoping, scope resolution, daemon, hooks, MCP) works unchanged.
Cursor / Claude Code agent
│ (edits a file)
┌────────────┴─────────────┐
│ │
edit hook typecheck_scope (MCP)
(record + pre-warm) (scoped diagnostics + types)
afterFileEdit / PostToolUse
│ │
└──────────┐ ┌──────────┘
▼ ▼
LSPSteer daemon ── warm pool, one server per project
│ (Unix-socket IPC)
▼
LSP client ──► typescript-language-server ──► tsserver
didOpen/didChange · publishDiagnostics · hover · documentSymbolThe steering note is built by (1) syncing the file to the warm server and collecting the diagnostics it publishes, (2) keeping only those overlapping the changed lines (plus a little context), and (3) resolving the in-scope types - the enclosing function's signature plus the resolved types of the identifiers in the changed region (via hover/documentSymbol). See docs/ARCHITECTURE.md.
npm test runs the hermetic component tests (LSP client, daemon IPC, MCP server). npm run e2e drives a live headless Claude Code agent and shows the steering loop end to end: with the agent denied Read, typecheck_scope is its only source of type info, and it goes from a TS2339 first guess to type-clean.
That demo isolates the mechanism but overstates the payoff. A controlled, paired A/B (eval/, 150 runs, scored by tsc --noEmit + held-out behavioral tests) gives the honest picture:
(0% to ~32-44%, McNemar p=0.013).
running tsc (first-diff 32% vs 36%, p=1.0), and final correctness is at ceiling because a capable agent self-corrects by reading.
So today the defensible claim is convenience and warmth, not a correctness win over the compiler. The advantage LSPSteer is designed for (diff-scoping when tsc dumps hundreds of errors, resolved types when reading is expensive) should appear on large repos, which the current suite does not cover. Full method and numbers: eval/README.md, eval/FINDINGS.md. Test ladder: docs/TESTING.md.
LSPSteer operationalizes, as a Cursor capability, a line of recent work on feeding program-analysis signals back into LLM code generation:
(PLDI 2025). Constraining decoding to the type system more than halves compilation errors and improves repair of non-compiling code. Background for why type signals are the right control signal.
(with syntax errors a small minority for TypeScript) - Mündler et al., PLDI 2025 - motivates targeting types rather than grammar.
the language server as a process-reward / retrieval source for agents. These are the closest prior work. LSPSteer differs on what it ships and where: it is not a CLI the agent shells out to or a retrieval index, but an always-on warm daemon wired into Cursor and Claude Code through their native MCP + hooks surfaces, returning a single diff-scoped steering note at edit time.
symbolic execution, and Agentic Code Reasoning (arXiv 2603.01896, 2026) - related uses of analysis signals in LLM reasoning, not editor-time type steering.
LSPSteer's contribution is not a new model or decoding algorithm; it is the editor-time plumbing - a warm, diff-scoped, type-resolving steering loop wired into the MCP + hooks surfaces of Cursor and Claude Code - that the above research implies but that no editor tool currently provides off the shelf.
Working end-to-end and verified: LSP client, diff-scoped analysis + type resolution, warm daemon with IPC, MCP server, hooks (Cursor and Claude Code), the init installer, and the CLI all run today - npm test exercises the LSP client, the daemon IPC path, and the MCP server against the bundled fixture. TypeScript is the proven language; Python/Rust adapters are stubs. The Stop-hook output contract is isolated in one harness-aware function (emitDecision) because the shape differs between Claude Code and Cursor (and has varied across Cursor versions).
MIT.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.