crux lsp
Language Server Protocol diagnostics, completion, navigation, hover, hints, and code actions for Crux projects.
crux lsp brings Project Index lint findings into editors that support the
Language Server Protocol. It publishes diagnostics for TypeScript and
JavaScript files, keeps their ranges aligned with unsaved edits, explains each
finding on hover, and offers the actions declared by its rule.
It also projects indexed definitions and relations into editor navigation,
symbols, definition hover, inlay hints, and code lenses. In supported
first-party dependency slots, it adds
Project Index-aware semantic completion.
Canonical md PromptText
also receives Markdown-aware highlighting, folding, headings, links, previews,
diagnostics, and safe refactors without replacing the native TypeScript
language service.
Command
crux lsp
crux lsp --port 4500
crux lsp --root packages/app| Flag | Default | Description |
|---|---|---|
--port <port> | 4400 | Local crux dev port to discover for attach mode. |
--root <dir> | . | Fallback project root when the editor sends no workspace folder or root URI. |
The command speaks JSON-RPC over stdio. Editors should start it directly as
crux lsp; do not wrap it in a shell or add a transport flag. Human-readable
logs go to stderr so stdout remains an LSP-only stream.
Attach and own modes
The language server chooses the read model independently for each Crux workspace folder:
- When a
crux devserver on the configured port reports the same project root, the language server attaches to its live Project Index. - When no matching server is available, it runs the same Project Index watcher in its own process.
- If an attached server disconnects, existing diagnostics stay visible while the language server reconnects. It falls back to its own watcher after the reconnect grace period.
- While indexing on its own, it periodically checks for a matching dev server and hands over without clearing diagnostics first.
A dev server for another project on the same port is never attached. A version mismatch produces a warning but keeps the server attached because the dev server's read model is authoritative.
Indexing remains save-based: unsaved content never changes Project Index results. The language server consumes incremental document changes to keep published ranges aligned with the edited buffer. While a document is dirty, new disk-derived positions are held until save so an authoritative reindex cannot move a squiggle back to stale buffer coordinates. Closing the document ends buffer tracking; the next authoritative update restores disk positions. Authoritative clears still apply immediately.
Semantic completion is the one feature that parses current unsaved text. Its bounded overlay is request-only and never becomes Project Index or cache state. See Semantic completion for supported slots, import behavior, privacy, limits, and exclusions.
Visual Studio Code and compatible editors
The Crux extension starts one language client for the window, discovers the
Crux binary, renders optional inline finding text and PromptText highlighting,
forwards server settings, and registers Crux: Open Devtools, Crux:
Restart Language Server, Crux: Preview PromptText Statically, Crux:
Preview PromptText in Application Runtime, and Crux: Open Latest PromptText
Run.
It activates in workspaces containing crux.config.ts, crux.config.js, or
crux.config.mjs.
The extension requires workspace trust. In Restricted Mode, the editor host does not activate it: no binary is discovered or started, and no workspace configuration is loaded. Granting trust activates the extension normally. The language server independently validates command actions and accepts only its fixed command allowlist as defense in depth.
Install the extension and CLI
Crux currently distributes its editor extension and native archives through GitHub Releases. The extension and CLI are versioned in lockstep. Choose the latest stable release for normal use; entries marked Pre-release are nightly builds from the exact source commit named in their release notes.
The recommended installation lets the CLI select, download, checksum, and install the VSIX from its own exact release:
npm install -g @use-crux/local
crux editor install vscode
# or
crux editor install cursorThe editor target is required; Crux never installs into every detected editor.
The installer verifies crux-vscode-<version>.vsix against that release's
SHA256SUMS before invoking code or cursor. It never falls forward or
backward to another release.
Crux is not published to Visual Studio Marketplace or Open VSX yet. A VSIX
installed from GitHub does not update automatically. Upgrade
@use-crux/local, then run the editor installer again.
For a project-local CLI, install the package in the workspace:
npm install --save-dev @use-crux/local
npx crux editor install vscodeWithout an explicit path, discovery checks repository build outputs, the
project-local node_modules/.bin/crux shim (crux.cmd on Windows), native
workspace executables including crux.exe, a workspace-root binary, and
finally PATH. The selected candidate must be executable and return a
non-empty version from --version. An invalid explicit crux.binaryPath is an
error and never silently falls through.
Direct download
As an npm-free alternative, download the VSIX, SHA256SUMS, and the archive
for your system from the same release:
| System | Archive |
|---|---|
| Linux x64 | crux-<version>-linux-x64.tar.gz |
| Linux arm64 | crux-<version>-linux-arm64.tar.gz |
| macOS Intel | crux-<version>-darwin-x64.tar.gz |
| macOS Apple silicon | crux-<version>-darwin-arm64.tar.gz |
| Windows x64 | crux-<version>-win32-x64.zip |
| Windows arm64 | crux-<version>-win32-arm64.zip |
Verify the downloaded archive and VSIX against their exact rows before extracting them:
grep ' crux-<version>-linux-x64.tar.gz$' SHA256SUMS | sha256sum -c -
grep ' crux-vscode-<version>.vsix$' SHA256SUMS | sha256sum -c -grep ' crux-<version>-darwin-arm64.tar.gz$' SHA256SUMS | shasum -a 256 -c -
grep ' crux-vscode-<version>.vsix$' SHA256SUMS | shasum -a 256 -c -$file = "crux-<version>-win32-x64.zip"
$expected = ((Select-String -Path SHA256SUMS -Pattern " $file$").Line -split " ")[0]
(Get-FileHash -Algorithm SHA256 $file).Hash.ToLower() -eq $expectedChecksums protect download integrity; the GitHub repository and release are the
publisher-identity boundary. Extract the archive and keep crux (or
crux.exe) beside crux-static-index-worker (or its .exe). Set
crux.binaryPath to the extracted CLI. Direct-download binaries do not update
automatically.
To download only the verified VSIX with an installed CLI:
crux editor install vscode --download-only ./artifactsInstall that file with Extensions: Install from VSIX..., or run:
code --install-extension ./artifacts/crux-vscode-<version>.vsix --force
cursor --install-extension ./artifacts/crux-vscode-<version>.vsix --forceFor a repository build instead, run pnpm install, build the extension, and
package it with pnpm --filter crux-vscode package.
Other LSP editors
Use the editor's custom language-server configuration with this equivalent shape:
command: crux
args: [lsp]
transport: stdio
languages: [typescript, typescriptreact, javascript, javascriptreact]
root_markers: [crux.config.ts, crux.config.js, crux.config.mjs]Pass --port <port> in args when crux dev does not use port 4400. Pass
--root <dir> only for clients that do not send workspaceFolders or
rootUri; editor-provided roots take precedence.
Bare clients must complete the standard startup handshake: send initialize
with the project rootUri or workspaceFolders, wait for its response, then
send initialized. Send initializationOptions.workspaceTrust: true to enable
completion and trusted actions. Keep reading stdout after initialized;
Project Index diagnostics publish when the first ATTACHED or OWN snapshot is
ready and do not require textDocument/didOpen. For ATTACHED mode, the
project root and --port must match the running crux dev server exactly.
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"rootUri": "file:///absolute/project",
"initializationOptions": { "workspaceTrust": true }
}
}Settings
VS Code settings use the names below. Other clients can send the same nested
crux object in initializationOptions or
workspace/didChangeConfiguration.
| Setting | Type / default | Effect |
|---|---|---|
crux.binaryPath | string, "" | VS Code extension only. Explicit CLI path; an invalid configured path is an error. |
crux.port | number, 4400 | Port used to discover and attach to a matching local dev server. |
crux.lint.profile | "", "off", "recommended", "strict", or "experimental"; default "" | Overrides presentation filtering. Empty follows the project's configured output; off publishes no findings. |
crux.lint.includeSuppressed | boolean, false | Includes findings retained with suppression evidence. They are hidden by default and shown as unnecessary when enabled. |
crux.inlayHints.enabled | boolean, true | Shows a finding-count hint on each indexed definition with current findings. |
crux.codeLens.enabled | boolean, true | Shows a finding-count code lens above each indexed definition with current findings. |
crux.decorations.mode | "auto", "on", or "off"; default "auto" | VS Code extension only. Controls inline diagnostic text; auto disables it when a supported general inline-diagnostics extension is active. |
crux.decorations.maxLength | number, 80 | VS Code extension only. Maximum inline decoration length, including its severity glyph, rule code, message, and additional-finding count. |
crux.decorations.opacity | number, 0.65 | VS Code extension only. Opacity from 0.1 to 1 for inline diagnostic decorations. |
crux.promptText.decorations.enabled | boolean, true | VS Code extension only. Controls Markdown-role highlighting inside PromptText. Disabling cancels pending work and clears every role immediately. |
crux.trace | "off" or "messages"; default "off" | Logs LSP method names without logging request or response payloads. |
Changing the lint profile or suppression setting re-filters the current read model without reindexing. Inlay-hint and code-lens changes apply live. Changing the port or binary path makes the VS Code extension restart the language client. Decoration settings are client-side presentation settings and are never sent to the language server.
Navigation and definition context
Crux navigation reads the same indexed definitions, source references, and relations as diagnostics:
- Go to Definition follows indexed source references and relation sites to their owning prompt, context, tool, agent, or other Crux definition.
- Find All References returns indexed relation and source-reference sites, with the declaration included when the client requests it.
- Document Symbols adds the file's Crux definitions to Outline.
- Workspace Symbols searches definition names and ids across Crux workspace folders. Results identify their folder in multi-root workspaces.
Navigation ranges use the displayed document view. They follow unsaved edits without reindexing, while newer disk-derived positions remain held until save just like diagnostic ranges.
Hovering an indexed definition shows its name, kind, description when present, current finding count, and incoming/outgoing relation counts. When a diagnostic also matches the position, the definition section follows the finding details.
Definitions with current findings receive two independent, live-configurable signals:
- An inlay hint such as
⚑ 2 findingsat the end of the definition's first source line. - A code lens such as
Crux: 2 findingsabove the definition. While attached tocrux dev, the VS Code extension makes it clickable and opens that exact definition in the Devtools Catalog. In own mode, or in clients that do not declare the client-side command, the count remains visible but informational.
Definitions without findings receive neither signal.
PromptText editor support
Crux recognizes PromptText only when semantic indexing proves that a tagged
template resolves to the canonical md export from @use-crux/core. Named
imports, import aliases, namespace access, and supported re-exports work. A
local md variable or lookalike tag receives none of these features.
Identity-sensitive features require saved semantic evidence whose generation and source hash match the editor buffer. Before dirty semantic overlays are available, changing a canonical template may temporarily clear highlighting, symbols, links, and PromptText diagnostics until save and reindex. Folding and static preview remain syntax-exact for the current buffer. Saved navigation can follow range transforms, but it never treats stale saved bytes as current PromptText evidence.
Highlighting, folding, symbols, and links
Mapped decorations distinguish headings, strong and emphasized text, links,
inline and fenced code, lists, and block quotes. Interpolations are barriers:
Crux never decorates through ${...}, so completions, hover, definitions,
rename, selection, brackets, and semantic highlighting inside an expression
remain native TypeScript behavior.
Colors come from ThemeColor, so Dark+, Light+, Dark High Contrast, Light High
Contrast, and later theme changes need no decoration rebuild or reparse.
crux.promptText.decorations.enabled: false affects highlighting only; folding,
symbols, links, previews, and diagnostics remain available.
Outline receives parser-produced heading labels and nesting. Folding covers
multiline headings, lists, block quotes, and fenced code without folding across
an interpolation. Literal links use their visible text range. Crux permits
hierarchical http/https URLs and lexically contained workspace-relative
paths; it rejects unsafe schemes, ambiguous encodings, and scope escapes. Link
validation performs no file read, stat, DNS lookup, or network request.
Static and exact preview
Crux: Preview PromptText Statically opens a read-only Markdown document
from the current buffer. Rust evaluates only syntax-exact scalars, arrays,
inert JSON, and proven same-document fragments. Unknown runtime values appear
as ⟪unknown⟫. The preview reports whether it is complete or truncated; it
never appends hidden source bytes to a truncated result and never executes
application code.
Crux: Preview PromptText in Application Runtime is available only for a
current semantic Prompt owner and an active crux dev runtime that published
that exact Prompt through configure({ prompts }). Devtools shows an explicit
confirmation before dispatch. Dispatch invokes observational preview() once. It
does not call a model, invoke tools, or create a Run or observability record,
but authored callbacks are trusted application code and may perform their own
I/O or side effects. Inputs and results remain in the active in-memory preview
session and are not placed in URLs, logs, caches, persistence, or broadcasts.
Latest Run
Crux: Open Latest PromptText Run resolves the current Prompt owner and the latest captured operation at click time. Ordering is by first observation, then operation ID, within one SQLite snapshot. The extension caches neither the owner nor a Run selection. If no Run exists, Devtools shows the Prompt's Catalog empty state and can link to exact preview when a matching runtime is currently available; it never dispatches a preview or navigates automatically when a Run later appears.
The opened ordinary Run can show the exact captured user prompt split into authored/static and interpolated/dynamic regions, with retained segment source and token attribution. This depends on normal observability input capture. String prompts and missing, invalid, truncated, disabled, or redacted provenance use the existing plain-text presentation.
PromptText diagnostics and quick fixes
Semantic indexing publishes three exact error diagnostics:
| Code | Meaning | Quick fix |
|---|---|---|
CRUX_PROMPT_TEXT_INLINE_SEQUENCE | A supported sequence is used inline. | Wrap the exact expression as (<expression>).join(", "), or use the Rust-proven Put sequence on its own line (changes layout) edit when available. |
CRUX_PROMPT_TEXT_INVALID_INTERPOLATION | The value is proven always invalid. | Serialize with md.json() only when the expression is proven applicable. |
CRUX_PROMPT_TEXT_JSON_SERIALIZATION | md.json() is proven to return no text. | Correct the authored value; no automatic rewrite is offered. |
Actions regenerate current syntax and semantic evidence and return one versioned edit. They never trust a previously published diagnostic payload. The editor preserves exact UTF-16 ranges for valid Unicode, CRLF, escapes, and cooked template text. It does not rewrite file encodings, normalize Unicode, repair invalid source bytes, or claim encoding diagnostics.
Diagnostics and actions
Diagnostics appear under the crux source and retain the rule's severity,
except experimental findings are shown as hints. Rule codes link to the rule
reference when the editor supports diagnostic code links.
Hovering a Crux diagnostic shows its title, rule id, severity, maturity, confidence, instance-specific message, rationale, impact, suppression details when available, and rule-documentation link. When several findings overlap, the hover includes up to three and reports the remaining count.
For rules with next-line suppression support, Quick Fix inserts the rule's
exact // crux-lint-disable-next-line ... directive above the affected line
while preserving indentation. Save the file to reindex it.
Some manual fixes also declare crux runtime generate as a companion command.
In a trusted VS Code workspace, their quick fix is titled
Run crux runtime generate (fix title). The server resolves the current
finding and fix from its read model, accepts only the exact built-in command,
and starts its own binary directly without a shell. It reports command success
or failure in the editor.
The command regenerates runtime artifacts; it does not rewrite the authored source that caused the finding. Make the documented source correction, run the command when appropriate, and save to clear the finding through normal reindexing. Command actions are unavailable in untrusted workspaces. Fix-all actions are not supported.
Inline decorations
The VS Code extension can render one compact annotation after each affected
line. It selects the most severe Crux diagnostic on that line, appends +N
when more findings share it, and uses the editor theme's diagnostic color at a
subdued opacity. Decorations read the editor's published diagnostics directly;
they add no language-server traffic and follow the same live range shifts.
crux.decorations.mode controls coexistence with general inline-diagnostics
extensions:
autoenables Crux decorations unless Error Lens (usernamehw.errorlens) or Reason Error Lens (PolyMeilex.reason-error-lens) is installed and active.onalways enables them.offclears them immediately.
Only visible editors are decorated. Suppressing a finding and saving removes
its annotation after the normal reindex unless suppressed findings are
included. Changing crux.decorations.opacity rebuilds the editor decoration
types and refreshes visible editors without restarting the language server.