# @okfit/lsp

> Language Server Protocol server for okfit: background diagnostics for an Open Knowledge Format (OKF) bundle in any LSP client, Claude Code included.

Latest version **0.3.0** (published 2026-09-24) · MIT license · 0 weekly downloads

## Install

```sh
npm install @okfit/lsp
pnpm add @okfit/lsp
yarn add @okfit/lsp
bun add @okfit/lsp
```

Provides the command `okfit-lsp`.

## Health

**Score 70/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; has provenance; recently updated; high maintenance score.

Warnings: low downloads; pre 1.0.

## Facts

| | |
|---|---|
| Version | 0.3.0 |
| Published | 2026-09-24 |
| First published | 2026-09-23 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM |
| Node | >=24.11.0 |
| Dependencies | 10 |
| Unpacked size | 155.2 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| GitHub stars | 0 |
| Author | C. Spencer Beggs |
| Maintainers | spencerbeggs |
| Keywords | okf, open-knowledge-format, lsp, language-server, claude, effect |

## Links

- npm: https://www.npmjs.com/package/@okfit/lsp
- Repository: https://github.com/spencerbeggs/okfit
- Homepage: https://github.com/spencerbeggs/okfit/tree/main/packages/lsp#readme
- Issues: https://github.com/spencerbeggs/okfit/issues
- npm.io page: https://npm.io/package/@okfit/lsp

## Dependencies (10)

- [effect](https://npm.io/package/effect.md) 4.0.0-rc.117
- [@okfit/core](https://npm.io/package/@okfit/core.md) 0.8.0
- [@effected/git](https://npm.io/package/@effected/git.md) ^0.17.0
- [@effected/xdg](https://npm.io/package/@effected/xdg.md) ^0.7.0
- [@okfit/engine](https://npm.io/package/@okfit/engine.md) 0.9.0
- [@effected/yaml](https://npm.io/package/@effected/yaml.md) ^0.17.0
- [@okfit/profiles](https://npm.io/package/@okfit/profiles.md) 0.8.0
- [@effected/markdown](https://npm.io/package/@effected/markdown.md) ^0.12.1
- [@effect/platform-node](https://npm.io/package/@effect/platform-node.md) 4.0.0-rc.117
- [vscode-languageserver](https://npm.io/package/vscode-languageserver.md) ^10.1.1

## Alternatives

- [mobx-react](https://npm.io/package/mobx-react.md) — 2.8M weekly downloads
- [rc-tree](https://npm.io/package/rc-tree.md) — 2.6M weekly downloads
- [@react-oauth/google](https://npm.io/package/@react-oauth/google.md) — 1.3M weekly downloads
- [@wagmi/connectors](https://npm.io/package/@wagmi/connectors.md) — 877.0K weekly downloads
- [vee-validate](https://npm.io/package/vee-validate.md) — 836.4K weekly downloads

## Recent versions

- 0.3.0 (latest) — 2026-09-24
- 0.2.0 — 2026-09-23
- 0.1.0 — 2026-09-23

## README

# @okfit/lsp

Language Server Protocol server for [okfit](https://github.com/spencerbeggs/okfit). Publishes background diagnostics for an Open Knowledge Format bundle into any LSP client, Claude Code included.

> **Part of the okfit kit.** Most users want **[@okfit/plugin](https://www.npmjs.com/package/@okfit/plugin)**, which pulls this package in automatically and launches this server through the Claude Code plugin's `lspServers.okfit` entry.

## What it is

`@okfit/lsp` speaks the Language Server Protocol over stdio for one or
more discovered OKF bundles. The `.md` binding is the client's own
registration (the Claude Code plugin manifest's `extensionToLanguage`);
this server answers for any document under a discovered bundle root. It
discovers a bundle per workspace folder the same way the CLI and MCP
server do, and
publishes `okfit validate`'s diagnostics as documents open, change, save,
or close. It
writes nothing to the bundle on its own -- every edit it computes (setting a
concept's status, appending a `verified` entry) is sent to the client as a
`workspace/applyEdit` request, never written directly, so the client remains
the one thing that ever touches disk.

## Launching it

Most users never invoke this directly — the Claude Code plugin's
`bin/start-lsp.sh` loader resolves the project's own
`node_modules/.bin/okfit-lsp` and falls back to `npx --yes @okfit/lsp`
when it is not installed. To run it directly, the package's own bin is
`okfit-lsp --stdio`; `--stdio` is accepted and silently ignored, since
streams are always stdin/stdout. `--node-ipc`, `--socket`, and `--pipe`
are not supported. `--clientProcessId=<pid>` is accepted, and the server
still exits on `exit`. The server's own signal that the client has gone
is its input stream closing; the underlying `vscode-languageserver`
library separately polls that process and exits with code 1 if it
disappears first.

## Publishing behaviour

- `didOpen`/`didSave` trigger a full revalidate; `didChange`/`didClose`
  trigger a cheaper edit-tier revalidate.
- The server registers no file watchers. When a client sends
  `workspace/didChangeWatchedFiles` itself, a change triggers a full
  revalidate on every live session. A config discovery file is the
  exception: it drops that folder's session, and nothing is republished
  until the next document event. Claude Code sends no watched-file
  events, so a config edit during a Claude Code session needs a session
  restart to take effect.
- A folder whose config fails to load is logged once and retried on the
  next `didOpen` or `didSave` under it, so fixing the config and saving
  a document recovers it.
- Exactly one `textDocument/publishDiagnostics` per file whose diagnostic
  set changed: an unchanged file is not republished, an emptied file
  publishes `[]`, and a file not open in the editor still publishes when
  its diagnostics change.
- A bundle-level diagnostic publishes against the bundle root's
  `index.md`.
- A non-`file:` URI, and any document outside every discovered bundle
  root, is ignored.
- Diagnostics for several files can arrive together in one client
  notification batch; in Claude Code that batch reaches the model's
  context on the next `Edit` or `Write` tool call, not immediately.

## Custom methods

Two `okfit/`-prefixed extensions, for editor front ends (the VS Code
extension's concept explorer); neither is part of the LSP standard, and the
LSP specification reserves `$/` for its own extensions, leaving vendor
prefixes to implementations.

- **`okfit/concepts`** (request, params `{}`) warms up every workspace folder
  that has never been resolved and runs a first revalidate for any bundle
  that has never loaded -- once per bundle root per session; a root whose
  bundle still fails to load after that first warm-up is not re-scheduled by
  a later request, only by a rebuild (a config fix, or the root's last
  workspace folder going away and a new one arriving) -- then answers with
  every live workspace folder's
  loaded bundle as `{ bundles: [{ root, rootUri, profile, concepts: [{ id,
  uri, title, type, status, stale }] }] }`: `status` is `"draft" | "stable" |
  "deprecated" | undefined` (absent when the frontmatter has none), `stale`
  is computed against the request time, and a bundle that still failed to
  load (no config, or one that failed) contributes no bundle entry.
- **`okfit/bundleChanged`** (notification, params `{ rootUri, reason:
  "revalidated" | "dropped" }`) is sent after every revalidate of a bundle
  root's diagnostics and after that root's session is dropped, so a client
  knows when to re-fetch `okfit/concepts`. The server advertises support with
  `experimental: { okfitConcepts: true }` in `initialize`'s result.

## Commands

`workspace/executeCommand` (the server advertises `executeCommandProvider.commands`
in `initialize`'s result) answers three okfit command ids. Arguments are
`ExecuteCommandParams.arguments`, an array positional by index; a wrong shape
fails naming what was expected. The ids sit under `okfit.lsp.` so they never
collide with a client extension's own command ids: `vscode-languageclient`
registers every advertised id as an editor command, and a duplicate stops the
client from starting.

- **`okfit.lsp.setStatus`** -- args `[uri, status]` (`status` one of `"draft" |
  "stable" | "deprecated"`). Computes the `TextEdit` that sets the concept at
  `uri`'s top-level `status`, sends it to the client with `workspace/applyEdit`,
  and answers the client's own `ApplyWorkspaceEditResult` verbatim.
- **`okfit.lsp.markVerified`** -- args `[uri]`. Computes the `TextEdit` that
  appends a `verified` entry (the resolved git identity, `Derivation.generatedBy`)
  to the concept at `uri`, sends it the same way, and answers the client's
  result. Fails when the concept is a draft, already verified by that actor,
  or no actor resolves.
- **`okfit.lsp.revalidate`** -- args `[rootUri?]`, or no arguments at all.
  Schedules a full revalidate (republishing diagnostics and sending
  `okfit/bundleChanged`) on the named bundle root, or on every live session
  when the argument is omitted, and answers `{ roots: [rootUri, ...] }` with
  the root URIs it revalidated -- `{ roots: [] }` for a root no live session
  resolves to.

Both edit commands, and the code actions, compute their edit against the
document's current editor text (or the file on disk when it is not open).
The commands send it as a versioned `documentChanges` entry over
`workspace/applyEdit`, so a client whose buffer has changed since refuses
the edit rather than applying it at stale offsets. A code action's edit is
not versioned on the client side -- `vscode-languageclient` and VS Code
both drop the version when applying a code action -- so it stays safe only
because it is computed from the current buffer at request time, not because
a stale one is refused.

## Status

Diagnostics, navigation, hover, code actions and commands, shipped through
phase 5 of the LSP roadmap; see the project's own
`okf/roadmaps/lsp-server-and-vscode-extension.md` for the full plan.

## License

[MIT](LICENSE)

---
_Source: https://npm.io/package/@okfit/lsp · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
