| Name | Modified | Size | Downloads / Week |
|---|---|---|---|
| Parent folder | |||
| semlith-v0.6.0-aarch64-apple-darwin.tar.gz | 2026-07-30 | 13.7 MB | |
| semlith-v0.6.0-aarch64-unknown-linux-gnu.tar.gz | 2026-07-30 | 16.6 MB | |
| semlith-v0.6.0-x86_64-pc-windows-msvc.zip | 2026-07-30 | 12.2 MB | |
| semlith-v0.6.0-x86_64-unknown-linux-gnu.tar.gz | 2026-07-30 | 15.5 MB | |
| SHA256SUMS | 2026-07-30 | 444 Bytes | |
| README.md | 2026-07-30 | 5.6 kB | |
| Semlith 0.6.0 source code.tar.gz | 2026-07-30 | 162.5 kB | |
| Semlith 0.6.0 source code.zip | 2026-07-30 | 182.2 kB | |
| Totals: 8 Items | 58.3 MB | 0 | |
semlith works from whichever agent you already use, the MCP tools cover the store rather than a fifth of it, and what counts as stable is written down.
Fixed
- The server no longer claims protocol revisions it cannot speak.
initializeanswered with whateverprotocolVersionthe client asked for, so a client on2026-07-28was told semlith spoke2026-07-28— a revision that had removed the very handshake it was answering. semlith now holds a list of the revisions it implements and answers with the requested one when it is on that list, or with the newest one it does implement when it is not.
Added
- MCP
2026-07-28, the stateless revision, alongside the handshake. That revision deletedinitialize, madeserver/discovermandatory and moved the protocol version onto every request. semlith serves both eras, deciding per message rather than per connection: a request carrying_meta.io.modelcontextprotocol/protocolVersiongetsresultType, server identity in_meta, andttlMs/cacheScopeontools/list; anything else gets exactly the answer 0.5.0 sent. A revision semlith does not implement comes back as-32022naming the ones it does.
The advertised list is 2026-07-28, 2025-11-25, 2025-06-18,
2024-11-05, and every entry has a recorded session in tests/mcp.rs
proving it. 2025-03-26 is deliberately absent: it is the only revision that
required JSON-RPC batching.
- Three more tools, so the MCP surface covers what the CLI does.
| Tool | What it does |
|---|---|
semlith_files |
Which files are indexed, narrowed by the same path/ext/lang/store, capped and saying how many it left out. |
semlith_index |
Index a path into an open store, so a corpus becomes searchable mid-conversation. |
semlith_forget |
Drop one file from a store. The file on disk is untouched. |
semlith_files exists because an agent that cannot ask "is this indexed"
reads an empty search result as "the corpus does not discuss this".
Both writers take the store's lock for the call and give it back, so a store
a semlith watch is holding comes back as a tool error naming the holder
rather than as a corrupted index. With more than one store open they require
a store argument: a store takes one writer, and there is no "the" store to
guess at.
semlith_index works to a wall-clock budget — 45 seconds, under the
60-second tool timeout clients default to — then returns what it reached and
how much is left. Calling it again continues rather than restarting, because
indexing has been keyed on content hashes since 0.1.0. It never creates a
store, so no tool call can contain a model download.
-
A setup stanza for every MCP client in common use, each verified against that client's own documentation: Claude Code, Claude Desktop, Codex, GitHub Copilot in VS Code, Copilot CLI, Cursor, Windsurf, Zed, Gemini CLI, JetBrains, Cline and Goose.
tests/clients.rsextracts every stanza from the README, parses it, and runs its command line against a real server, so a flag renamed in the code and not in the README fails the build rather than somebody's first attempt. -
docs/compatibility.md— which surfaces are a contract (CLI commands and flags, MCP tool names and schemas, the advertised protocol revisions, the store on disk, thelib.rsAPI) and which are free to change (ranking scores, human-readable output, stderr, the default model, additive JSON fields). It is explicit that 0.x is what backs the promise. -
format_versionin the store's meta table. A store created by 0.6.0 records format 1; a store written before the key existed is read as format 1 and never rewritten; a store from a format the binary does not know is refused naming both numbers instead of misread. Written down now, while nothing has changed, so the first change that does happen fails loudly. -
SEMLITH_MCP_INDEX_BUDGET, in seconds, for a client whose tool timeout is not the usual one. -
The MCP server says what it is on stderr — the stores it opened, and the revision it negotiated when that differs from what was asked. stdout is the protocol; stderr is the only channel a stdio client captures, and "the agent sees no tools" was otherwise undiagnosable.
Changed
semlith forgettakes the store's write lock. It rewritesindex.tvexactly as indexing does, so it is a writer and now waits its turn like one. Aforgetthat ran whilesemlith watchwas saving could leave the index and the database disagreeing about which chunks exist. It now exits non-zero naming the holder instead.
Performance
Measured on an Apple M1:
- The tool list grew from 2220 bytes for two tools to 4790 for five — roughly 555 estimated tokens to 1197, measured through both release binaries. It is loaded into an agent's context once per session whether or not a tool is called, so three more tools cost about 640 tokens a session.
- An MCP server at rest holds no store lock:
semlith indexin another terminal against the store an open server is serving succeeds.
Install
Download the archive for your platform, unpack it, and put semlith on
your PATH. Linux builds need OpenBLAS at runtime
(apt-get install libopenblas-dev or your distribution's equivalent).
Intel macOS has no prebuilt binary: ONNX Runtime no longer publishes
x86_64 macOS builds.
Verify a download against SHA256SUMS before running it.