rust-lang / rust-lang/rust-analyzer

experimental/serverStatus: tell clients when answers to workspace-wide requests are complete (a readiness field, or a successor notification)

Open
#23,331 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-lsp C-feature
Dominant language
Rust
Stars
16.9k
Forks
2.2k
Avg merge
1d 12h
Merged PRs (30d)
72

Description

Summary

experimental/serverStatus is documented as a status line for the end user, and quiescent answers "is there pending background work?". A client that needs to know whether an answer to references, workspace/symbol, rename, … is complete has to read quiescent as "ready", and that reading is wrong at the moment it matters most: before the first workspace has been loaded, the server is trivially quiescent. rust-lang/rust-analyzer#10888 asked for a readiness notification and was closed as "already exists" pointing at serverStatus; this issue is about the part that does not exist yet, with two implementations to choose from. I will open a PR for whichever you prefer.

What a client sees today

Measured with rust-analyzer 2026-08-03 (nixpkgs) over stdio, the client declaring experimental.serverStatusNotification (script: https://github.com/tagawa0525/lsp-det/blob/main/scripts/rust-analyzer/status-probe.py):

  • A directory without Cargo.toml: the first notification, 5 ms after initialized, is {health: "warning", quiescent: true, message: "Failed to discover workspace. …"}. Nothing has been loaded and the fetch has not started (GlobalState::run reports the status before fetch_workspaces_queue.request_op("startup")). quiescent: true here means "nothing in flight", not "ready". 1 ms later: {health: "error", quiescent: true, …}.
  • A one-crate project: {quiescent: false} at 5 ms, {quiescent: true} at 1.7 s. The initial last_reported_status is quiescent: true, so a client that missed a notification (there is no request form) has to assume the server is ready.
  • The doc says "this functionality is intended primarily to inform the end user … Clients are discouraged from but are allowed to use the health status to decide if it's worth sending a request." There is no field a client may rely on for completeness.

Coding agents are the client that needs this: they send references right after starting the server and take an empty answer as a fact (anthropics/claude-code#76870). Zed already reads serverStatus (crates/project/src/lsp_store/rust_analyzer_ext.rs), so there is a consumer for whichever shape is chosen.

Option A: a readiness field in ServerStatusParams

Branch: https://github.com/tagawa0525/rust-analyzer/tree/server-status-readiness

interface ServerStatusParams {
    health: "ok" | "warning" | "error",
    quiescent: boolean,
    /// initializing: no workspace loaded yet.
    /// indexing: workspaces are being (re)loaded or caches primed; answers may be incomplete.
    /// ready: fully loaded; answers are complete.
    readiness: "initializing" | "indexing" | "ready",
    message?: string,
}

Computed from the same facts as quiescent: initializing while workspaces is empty and no load has failed, ready when is_fully_ready(), indexing otherwise. The initial last_reported_status starts at initializing, so the notification traffic does not change. The doc paragraph is amended: this field, unlike the others, is meant for clients that decide whether to trust an answer. quiescent, the VS Code extension and every other client keep working as they are.

Measured on the branch: initializing (4 ms) → indexing (0.2 s) → ready (0.54 s) on the one-crate project; initializing{health: "error", readiness: "ready"} on the directory without Cargo.toml (a failed load is reported on the health axis, and readiness says the failure is settled).

Smallest change. What it does not give: a request form (a client that attaches late waits for the next notification), and a declaration of what ready covers.

Option B: a successor, experimental/serverState

Branch: https://github.com/tagawa0525/rust-analyzer/tree/server-state

A request experimental/serverState answering {health, readiness, message} at any time after initialize; a notification experimental/serverStateChanged sent when health or readiness changes, if the client declares experimental.serverState; and a server capability serverStateProvider that declares the guarantees by naming what is missing (coverage: {scope: "workspace", incomplete: {"workspace/symbol": <workspace.symbol.search.limit>}}, freshness: {fileChanges: ["Created", "Changed", "Deleted"]}). serverStatus is untouched. An undiscovered workspace is health: "error" there (nothing workspace-wide can be answered), which A leaves at warning for compatibility.

The vocabulary follows the server state protocol specification (https://github.com/tagawa0525/lsp-det/blob/main/docs/spec/server-state.md), written as a candidate for LSP itself; serverStatus is the closest existing vocabulary and the one it was modelled on.

Either way

lsp-det, a transparent proxy that derives the same three values from quiescent today, reads the field when present (A) or passes the notification through untouched (B), so agents that already sit behind it are covered by both. Both branches pass cargo xtask tidy and the rust-analyzer lib tests, with lsp-extensions.md and its hash updated.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by comparing the two linked branches and read the existing serverStatus implementation around GlobalState::run, then inspect lsp-extensions.md and the mentioned Zed consumer. Run cargo xtask tidy and the rust-analyzer lib tests to understand the current validation; done means one protocol shape is selected, documented, tested, and the extension hash is updated.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend-api-design, developer-experience, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.