Skip to content

lsp: design RFC for the language intelligence family - #86

Merged
pcarrier merged 6 commits into
fsfrom
lsp-rfc
Jul 23, 2026
Merged

lsp: design RFC for the language intelligence family#86
pcarrier merged 6 commits into
fsfrom
lsp-rfc

Conversation

@pcarrier

Copy link
Copy Markdown
Contributor

Draft RFC for a third protocol family (FEATURE_LSP, bit 8, opcode block 0x60) exposing language intelligence to blit clients: docs/design/lsp.md.

Architecture: terminate-and-project. The server hosts warm language-server processes like PTYs — daemon-owned, keyed by (canonical_root, server_id), surviving disconnects — and is each one's sole LSP client. Clients speak blit records only: no JSON-RPC, no capability negotiation, no UTF-16. This is the shape Zed / JetBrains Gateway / Live Share converged on; every raw-LSP multiplexer (lspmux, lspd, ra-multiplex) documents the failure modes (id rewriting, capability intersection, dropped server→client requests, didChange version corruption) that N=1-by-construction dissolves.

Wire, along the family grain:

  • LSP_STATE — server phase/progress/capabilities/RSS as coalesced whole snapshots (GIT_STATE pacing)
  • LSP_DIAG — per-file replacement sets from a server-held last-per-file cache, FULL replay on every subscribe (a one-shot CLI or late-joining tab never sees a blank gutter)
  • LSP_QUERY — one opcode, kind byte (definition / references / hover / doc & workspace symbols / rename-as-data), skippable response records
  • Positions are 0-based line + UTF-8 byte column both directions; the server transcodes to each backend's negotiated encoding. LOCATION/DIAG_FILE carry BLAKE3-128 content hashes, composing with FS_SYNC for staleness.

Stances taken: disk is the only document truth (sync is server-driven; dirty-fed LRU open set for open-doc-only servers like tsserver/pyright/clangd); read-only by construction (applyEdit refused, rename returns its plan as data; write-shaped features gated on the mutation/buffer RFC); zero-config discovery via per-server root policies over a compiled marker table, commands never defined by repository contents; budgets that degrade (WARMING, truncation flags, spawn-rate/restart caps); rollout carries an agent-adoption kill gate after the CLI ships.

Stacked on #85 — the doc links fs-watch.md/git.md and reuses the fssync shared-root watcher, gix root discovery, and family conventions introduced there. Retarget to main once #85 merges. Doc-only change; no code.

🤖 Generated with Claude Code

Proposes FEATURE_LSP (bit 8, opcode block 0x60): the server hosts warm
language-server processes the way it hosts PTYs, acts as each one's
sole LSP client, and projects LSP into blit-native records — server
phase and capabilities as coalesced state snapshots, diagnostics as
per-file replacement sets replayed in full to fresh subscribers, and
definition/references/hover/symbols/rename-as-data as nonce pulls
through a single query opcode with skippable record kinds.

Positions are 0-based lines with UTF-8 byte columns in both
directions; the server transcodes to each backend's negotiated
encoding against canonical bytes, so no client ever learns UTF-16
exists. Disk is the only document truth and document sync is
server-driven: the fssync shared-root watcher feeds
didChangeWatchedFiles, and a dirty-fed LRU open set serves
open-doc-only servers. Read-only by construction — rename returns its
edit plan as data, applyEdit answers applied:false, and every
write-shaped feature is gated on the anticipated mutation/buffer RFC.

Zero-config discovery walks per-server root policies over a compiled
marker table; commands come only from the table or user config, never
repository contents. Terminating LSP server-side dissolves the
documented multiplexer failure modes (id rewriting, capability
intersection, dropped server->client requests, didChange version
corruption) by making N=1 by construction, and keeps every client —
browser, CLI one-shots, SDK — a thin apply-records-and-ack consumer
sharing one warm backend per workspace.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown

Coverage

Crate Lines Functions Regions
alacritty-driver 69.7% (698/1002) 72.0% (54/75) 71.7% (1050/1464)
browser 0.0% (0/807) 0.0% (0/65) 0.0% (0/1370)
cli 21.4% (1334/6235) 33.8% (182/538) 24.7% (2426/9814)
compositor 1.0% (93/9245) 2.0% (8/400) 1.2% (146/12422)
fonts 76.8% (486/633) 85.5% (47/55) 77.9% (922/1183)
fssync 90.1% (1922/2134) 91.8% (156/170) 90.4% (3272/3621)
gateway 25.5% (362/1419) 29.0% (36/124) 19.3% (449/2332)
git 80.2% (1896/2364) 83.4% (146/175) 80.7% (3088/3828)
lsp 68.1% (1567/2301) 70.7% (152/215) 66.1% (2443/3697)
proxy 19.4% (173/892) 21.3% (27/127) 21.4% (295/1381)
remote 87.1% (5720/6565) 90.5% (418/462) 84.6% (9419/11127)
sd-notify 73.9% (68/92) 100.0% (6/6) 83.2% (109/131)
server 22.1% (2813/12704) 35.8% (293/819) 23.7% (4715/19867)
ssh 1.9% (7/374) 3.2% (1/31) 0.7% (4/613)
upsidedown 31.4% (391/1247) 27.8% (55/198) 34.8% (797/2287)
webrtc-forwarder 2.7% (72/2624) 2.1% (4/187) 1.2% (50/4335)
webserver 63.5% (753/1185) 70.8% (121/171) 67.8% (1380/2034)
Total 35.4% (18355/51823) 44.7% (1706/3818) 37.5% (30565/81506)

pcarrier and others added 3 commits July 23, 2026 00:32
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Server-side implementation of FEATURE_LSP (bit 8, opcode block 0x60):
warm language-server backends, daemon-owned and keyed by
(canonical_root, server_id), shared across connections and surviving
client disconnects. blit is the sole LSP client of each child and
projects LSP into blit-native records — clients carry no JSON-RPC, no
UTF-16, no capability negotiation.

New crate blit-lsp: discovery (per-server root policies over a compiled
marker table, verbatim-JSON config pass-through), a supervised
JSON-RPC stdio client on a non-blocking writer thread, and a projection
engine per backend that owns initialize, the dirty-fed LRU open set,
the last-per-file diagnostics cache with FULL replay-on-subscribe, and
UTF-8-byte <-> negotiated-encoding position transcoding. Server->client
requests terminate in blit (workspace/configuration from config,
applyEdit refused and counted, progress to phase). A scripted
in-process fake LSP server drives the engine tests; verified end to end
against clangd (definition, references, hover, symbols, rename-as-data,
the edit->diagnose loop, stop-and-respawn).

- crates/remote/src/lsp.rs + js/core/src/lsp.ts: wire codecs and the
  LspStateMirror / LspDiagMirror reducers, byte fixtures pinned across
  both implementations
- crates/server: dispatch, per-connection attachments over the shared
  registry, feature gating, refusal tests
- crates/cli: blit lsp def|refs|hover|symbols|diagnostics|rename|wait|
  list|stop, NDJSON, 0/1/2 exit codes, learn.md section
- js/core: openLsp on BlitConnection with paced state/diag mirrors

Positions are 0-based lines with UTF-8 byte columns both directions;
LOCATION/DIAG_FILE carry BLAKE3-128 content hashes that compose with
FS_SYNC for staleness. Discovery degrades silently when a server is
absent, naming it in LSP_OPENED so a client learns what to install.
Read-only by construction; write-shaped features gated on the mutation
RFC.

Applies the fixes from the adversarial review of this branch: drain
queued queries on engine stop so no nonce leaks; LSP_STOP drops the
SERVER record and a later query respawns; non-blocking child writes;
kill-escalation and selective PTY-pid reaping so an LSP child leaves no
parked status to collide with a recycled pid; defer didOpen replay past
initialize; honor publishDiagnostics version; duplicate-nonce guards;
FULL-diag byte budget; sweeper TOCTOU; query-only attachments count
against idle; MAX_DOCS floor; diag --wait no longer spins or hangs on a
failed backend; INCOMPLETE flag when a rename plan drops file
operations; reset LSP attachments on transport drop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

🔗 Preview: https://blit-k1sz204nj-indent.vercel.app

pcarrier and others added 2 commits July 23, 2026 02:06
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@pcarrier
pcarrier merged commit 1100981 into fs Jul 23, 2026
11 of 12 checks passed
@pcarrier
pcarrier deleted the lsp-rfc branch July 23, 2026 00:29
@pcarrier

Copy link
Copy Markdown
Contributor Author

Folded into #85 — all commits from this branch are now in fs, which #85 targets. Closing here; review continues on #85.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant