Changelog
Every release of the open-source semlith binary, newest first: what it changes for you, and the headline of each change, with the full notes on GitHub.
Each release below opens with what it changes for you, then lists the headline of every item. Its full notes, with the reasons and the measurements, are on GitHub, linked under its version.
0.49.0
28 October 2026 · Full notes on GitHub
A machine with no network indexes and searches a folder that holds images, once its model cache is copied from a connected machine. No store format change and no re-index.
Added
semlith setup --all-models- The Privacy page lists every model weight
tests/airgap.sh
Fixed
- A pictured query no longer fails when CLIP’s text encoder is missing
- Indexing an image fetches both CLIP encoders
- A cached rescoring model loads under airgap
0.48.0
27 October 2026 · Full notes on GitHub
docs.rs, crates.io, semlith --help and the README describe Semlith in the same words and link semlith.com. The binary does, sends and stores exactly what 0.47.1 did.
Changed
- The crate docs open with the repo tagline
- crates.io links the website
- The README links the website
0.47.1
25 October 2026 · Full notes on GitHub
Fixed
- A folder named in a path filter matched nothing
0.47.0
24 October 2026 · Full notes on GitHub
The README and the portal talk about Semlith. The binary does, sends and stores exactly what 0.46.4 did.
Changed
- The README names Semlith Cloud only as a separate hosted service
- Settings › Cloud, signed out, states the one sentence on both products
- The MCP registry entry publishes itself
0.46.4
24 October 2026 · Full notes on GitHub
Docs and metadata only. The binary behaves as 0.46.3.
Changed
- The README’s first screen is back in the usual order
- README claims match the code
- README prose
- Crate and registry description
0.46.3
24 October 2026 · Full notes on GitHub
Test harness only. The binary behaves as 0.46.2.
Fixed
- The browser drive no longer fails a release for a request the browser never sent
0.46.2
24 October 2026 · Full notes on GitHub
Metadata only. The binary behaves as 0.46.1.
Added
glama.json
0.46.1
24 October 2026 · Full notes on GitHub
Docs, metadata and one workflow. The binary behaves as 0.46.0.
Added
- Listed in the official MCP registry
Changed
- The README leads with what semlith changes for an agent
- Dependencies
Fixed
- The clean-install workflow’s Windows tamper check works again
0.46.0
24 October 2026 · Full notes on GitHub
The two security audits of 0.45.1 (2026-10-23) found nothing Critical or High. This release closes all eighteen of their findings, or records why one is accepted. Each fix comes with a test that fails on 0.45.1.
Security
- Only a commit on main can become a signed release (SEC-001)
- Each release job holds one permission (SEC-007)
- The installers check who built a release, and refuse an old one (SEC-007, SEC-015)
semlith addnever fetches through a proxy (SEC-003)semlith upgradeunpacks the bytes it checked (SEC-004, SEC-014)- Packs and the embedding model are used as they were checked (SEC-004)
- On macOS, a native parser cannot grow past its worker’s memory limit
- Isolation headers (SEC-015)
- Every lockfile is audited (SEC-010, SEC-011, SEC-013, SEC-016)
- A secret scan gates every push (SEC-002)
Changed
- CI decides more carefully what is prose (SEC-005, SEC-006)
- The bug hunt in
native-smoke.ymlreads its own budget-cappedANTHROPIC_BUGHUNT_KEYand skips without it
Accepted
- A process running as you that writes the model cache while the daemon runs could change an unpacked pack’s files, or the model graph ONNX Runtime opens by path, after the check
- Two expired confidential-VM attestation tokens remain in the history behind the v0.37.0-rc.5 and rc.6 tags, which the tag ruleset keeps immutable
0.45.1
21 October 2026 · Full notes on GitHub
Changed
- The README and the clients guide say what the binary does
0.45.0
21 October 2026 · Full notes on GitHub
Added
- Settings › Cloud shows the org’s stores this machine has not connected
semlith cloud statussays which stores are connected here- The Stores page’s Remote stores card
Security
- rustls-webpki 0.103.16 and webpki-roots 1.0.10
0.44.1
19 October 2026 · Full notes on GitHub
Added
- The documents benchmark is in the repository
- The README’s first screen
Fixed
- A call with no receiver resolves to the function it names, not a tie with a method
- A method that calls the free function of its own name records the call
- Two definitions of one name in one file keep their own calls
- Members and top-level functions are told apart in every language
- Go methods are qualified by their receiver type
- A Rust integration test is not a library function
- A call into the standard library no longer lands on a namesake in your code
- JavaScript member calls are calls through a receiver
- A grouped Rust
useplaces what it imports - A Rust
fnin a module body is a function - The extractor changes above take effect as files are re-indexed; the resolver changes answer at once
- A live Slack token no longer reads as a typed placeholder by chance
- Portal dialogs scroll instead of clipping
0.44.0
18 October 2026 · Full notes on GitHub
Added
- Any number of remote workers
Fixed
- Calls inside Rust macro arguments are calls
- The CPU-backed worker lane is not refused as a software renderer
Upgrading
- Library:
accel::lanereturns an ownedArc<Lane>;accel::Enabled.remoteis nowremotes(the remote lanes switched on);accel::Switchesgainsremotesand is no longerCopy
0.43.0
17 October 2026 · Full notes on GitHub
Fixed
- A printed report keeps every column
- semlith’s own PDF prints ids and paths whole
- The change brief finishes
- A team member’s local use counts in the cloud
semlith cloud pushsays what it leaves out--outtakes a foldersemlith_filessays the total first
Security
- SK30, DNS rebinding in
semlith_add - zip 9.0.4
Changed
- Dependencies: fastembed 7.1.1, serde_json 1.0.154, sha2 0.11.1, tree-sitter 0.27.1 and tree-sitter-erlang 0.21.0
0.42.0
17 October 2026 · Full notes on GitHub
Added
- Many agents, one consistent store
- A run is answered from before it until it commits
- MCP 2026-07-28 clients are named
- Chain v2
- The watcher wakes the embedding lanes on the first change
Changed
- Break, 2026-10-16: the whole-file side of a saving is what reading the file costs
- One aggregation behind every figure
semlith_read,semlith_pattern,semlith_impactandsemlith_traceare recorded with what they returned, from MCP, the CLI and the portal; a graph answer is one row, in the store that answered- The tool-list cost is one count, bytes over four: the gate in
tests/retrieval.rsand the Agents page print the same number - Every report looks like Semlith, in every format
- Break: CSV and JSON are data
- Break: one default window, and it applies to every figure
- Break: a schedule replaces one file in place
- Numbers in reports print
736,397, as the portal does, through one formatter - The change brief counts every file it re-read (no per-store cap of 200), does not call a first index a re-read, and carries the blast radius of the changed definitions from the impact walk; paths print relative to the store’s root
- The Reports page previews the rendered HTML in a sandboxed frame under a report-only policy; Copy stays Markdown
semlith_reporttakeswindow,scope,redact,excerptsandtable- The settled share drops, and that is the honest number
Fixed
- Clocks: a row is printed with the UTC offset in force when it was written,
semlith ledgerprints the date on rows older than today, and the portal pairs the local date with the local time (an IST row at 03:00 on 10-10 read “10-09 03:00”) - A run’s card, history and log events give the work’s own time, not the time the wizard sat on its Review page (41 s of work read “done in 1m 31s”); a time left that had counted down to a second rises again when the rate falls; the CLI prints the last twenty seconds’ chunks/s; a catch-up that found nothing to embed no longer leaves the store’s last run reading “0 / 233 chunks”
cloud statusand the portal say when the cloud last checked a source (“checked 14 h ago”), floored the same way, never “behind” for an index at the branch headsemlith refused --store Xlists X only with a daemon running;semlith priceslists its table- The portal prints the daemon’s real store home, the Privacy page lists files
semlith addfetched, a registration that cannot reach this daemon is not counted as registered, Review lists every dotfile the hidden rule skipped, and an encrypted document or an archive past the 32 MiB budget says so rather than “no text layer” - A Neural Engine worker waiting on the Core ML compile lock leaves when the process that started it has gone
- A Core ML worker removes only earlier protocols’ worker copies, never a later one’s
- A file whose first 8 KiB is mostly invalid UTF-8 or control characters is refused as binary with the share in its reason (ripgrep’s
sherlock.br, a Brotli file with no NUL, became one chunk of U+FFFD) - No call edge claims a call that does not exist (G1)
- Missed callers and mislabelled edges (G2, G3, G8)
- Python owners and alias spans (G4, G5)
- Setext Markdown headings (G6)
symbolcounts and orders (G7, G9, G10, G11)- “Called and not found” is code the corpus does not hold
- Asking for fewer results only cuts the answer (G12)
- A question about code is answered with code (G13)
readprints every line of its range (G14)- brief spends its budget in the order its help states and names every drop (G15, G16)
- Markup is read and searched as written (F13)
- A local store and its remote mirror answer once (F21)
Security
- A redacted report’s query digest is keyed with a per-machine salt (
~/.semlith/report.salt); the unkeyed digest could be reversed by hashing a corpus’s own symbol names - What a code store holds of an HTML file
0.41.0
15 October 2026 · Full notes on GitHub
Security
.gitand credential folders stay out, wherever they are (S12)- Every read of a file’s bytes refuses a link (S13)
- The session token is never in a log file (S14)
- Model files are checked before they are loaded (S15)
- Exports cannot run anything (S16)
- Paths are quoted for where they are written (S17)
- One file costs seconds, not CPU-minutes (S18)
- Developer overrides are not in the release binary (S20)
- A search can stay on this machine, and the Privacy page says when it does not (S21)
addconnects to the address it checked (S22)- Small surface issues (S23)
- Store hygiene (S24)
- SECURITY.md says what is true (S25)
- The gate that stays (S19)
Fixed
- Three parser inputs found by the new fuzzers
- The review list no longer fills with build churn
- The Linux login service serves
- Renaming or deleting a store on Windows
0.40.0
15 October 2026 · Full notes on GitHub
Security
- A file can no longer crash semlith (S01, High)
- Agent keys are read-only by default (S03)
- One slow call no longer stalls every agent (S02)
- read never serves what a link points at (S05, S13)
- cloud login opens only the host’s own page (S04)
- A repository’s config runs nothing (S07)
- llama-server’s key is off the command line (S08)
- Config rewrites keep modes and links (S09)
- A refused secret leaves nothing behind (S10)
- Releases are signed (S06)
- Idle sockets no longer lock anyone out (S11)
- cargo audit on every push
Fixed
- Three index-time races
- Decisions shows a retried file’s outcome without a reload
0.39.0
13 October 2026 · Full notes on GitHub
Changed
- A first import commits less (#210)
- Store format 5: turbovec 1.1 (#219)
Fixed
- The credential-scan test no longer fails on an unlucky draw (#222)
0.38.1
12 October 2026 · Full notes on GitHub
Fixed
- A cached vector made on another lane is used
0.38.0
10 October 2026 · Full notes on GitHub
The public scorecard
bench/scorecard/reproduces every published number
Documentation
- The README and the documentation are rewritten to the point
Fixed
- A long query no longer puts a screenshot first
- A file emptied on disk is evicted from the store
- A scope’s first search no longer pays the whole filter resolution each time the scope changes (#183)
- A failed accelerator lane is tried again (#188)
- A live secret that opens on
FAKEby chance is no longer a dummy - A search hit is named for the definition it is mostly about
- The run card’s drain line counts down
- Home tells agents apart from the portal
- A report saved after midnight is named for the right day
semlith accel --help- A test no longer deletes the login service
0.37.0
9 October 2026 · Full notes on GitHub
The Semlith Cloud client leaves release candidate. Everything rc.1 to rc.7 carried ships here; the sections below them say what each added. Nothing changes for anybody who never signs in: with no ~/.semlith/cloud.json the binary makes no connection to Semlith Cloud at all.
In this release, from rc.1 to rc.7
- Semlith Cloud, from this machine
- Images indexed by their bytes, not their extension (rc.2)
- A vector cache a library caller can give a store of its own (rc.3)
- An index run that tells the truth about itself everywhere it is shown; the image lane on a thread of its own; checkpoints that no longer drain the lanes; WebGPU on NVIDIA checked against its Vulkan driver (rc.4)
- A CPU cap, 0-100 % of semlith’s own process (
SEMLITH_CPU_CAP, the Limits card, in steps of 5); the CPU lane always on; lanes this machine’s hardware cannot run refused at the switch (rc.6, rc.7)
Removed
- The
remotelane andsemlith worker ledger::measure, which had no caller in the binary- The direct
rustls,rcgen,ringandbase64dependencies, which only the remote lane used
Changed
- The published crate carries the source, the tree-sitter queries, the files the binary compiles in and the notices; tests, harnesses, docs and CI stay in the repository
0.37.0-rc.7
9 October 2026 · Full notes on GitHub
Changed
- The CPU cap steps by 5
0.37.0-rc.6
8 October 2026 · Full notes on GitHub
Added
- A CPU cap
Changed
- The CPU lane is always on
- The switches tell the truth
Fixed
- A first index through a remote GPU is 1.39x faster (#207)
imagesinindex -v’s write parts now counts only the writer’s work, not the image model’s own thread
0.37.0-rc.5
7 October 2026 · Full notes on GitHub
Added
- A
remoteembedding lane, attested before anything is sent - The portal’s lane row and
doctor --gpusay where the remote lane points and what its attestation proved - People with their own NVIDIA GPU: the CUDA and TensorRT lanes documented and measured (both cosine 1.0000)
0.37.0-rc.4
6 October 2026 · Full notes on GitHub
Fixed
- An index run tells the truth about itself, everywhere it is shown
- A run no longer stops to drain at each checkpoint (#203)
- Images are embedded on a thread of their own, so the text lanes keep embedding while the image model works; it had run on the writer and left the Neural Engine idle through a stretch of screenshots (#203)
- A run admitted behind another job on its store’s writer can be taken out of the queue; the button said “nothing waiting in the queue”
- Time left counts the embedding alone
- The images total counts images with the image model and, on a reviewed run, the plan’s from the first second (it read 1 / 34, then 2 / 18, then 55 / 55); the drain’s “still embedding” no longer counts the window being filled twice
- A long run gives the writer to file changes in its folders every five minutes rather than every 45 seconds, since each hand-over drains the lanes; a queued job still waits at most 45 seconds
- Creating or deleting a store no longer waits for a search or graph in progress to finish
- A phase said again with nothing new is logged once; under a stage filter the log folds a phase line that repeats the last one shown
- The run log has one reader per run, shared by every card that shows it: the wizard’s rebuilt card added every line twice
- A progress bar redrawn in place moves: the page patched its width as a style attribute, which the portal’s content-security policy drops, so the bar kept its first width while its percentage climbed
- The WebGPU lane on Linux refuses to start when Vulkan has only a software device, and names the hardware device it uses
- A failed accelerator lane is tried again on the first run ten minutes after it failed, and the failure is written to the daemon’s log
- A scoped search is no slower than an unscoped one on a large store: a
<repo>/**scope is a range of a path index rather than a GLOB over every path, and the eight most recent resolved scopes are kept, so an agent moving between repositories does not resolve each one again (#183) - A file that became empty, too large or unreadable is evicted, so its old chunks stop answering searches; an unusable image’s vectors go with its rows
- A query longer than CLIP’s 77 tokens is never a confident image match
- A key-like secret whose random part happens to open on
FAKEorDUMMYis no longer taken for a declared test dummy - Long log lines, attention rows and feed entries in the portal wrap instead of cutting off the reason
measure_the_store_at_scaletakes each size’s idle RSS as the median of five fresh opens, so a bimodal first figure on a hosted runner no longer fails the release suite (#199)
Added
- The portal matches Semlith Cloud on what the two share: full text on hover for anything cut off and a tip on every progress bar; sortable columns marked; filters and tabs kept across a reload, and the setup wizard too; a busy wizard button that says what it is doing; search store chips, the budget tip and the store before each result path; the ledger’s read bars on one scale (a session that sent more than the whole file overflowed), its savings tables and chain footer; a “chain verified” chip on reports; a store error card and nav badge, an empty Stores state and a Sources table in Inside the index; the Review tab’s loading state and the wizard’s “nothing in the grey zone” note
Changed
semlith index -vsplits the writer’s time by part: rows and their keyword index, eviction, graph, vectors, commits, saves, hashes and the vector cache (#198)- A failed known-answer check names every chunk under the floor, not only the worst (#197)
semlith setupsays what--hook-mode gatebuys where the choice is made, and docs/clients.md records the measurement behind it (#189)
Security
- rustls 0.23.45, past RUSTSEC-2026-0285 (TLS 1.3 handshake messages accepted across encryption levels)
0.37.0-rc.3
5 October 2026 · Full notes on GitHub
Added
- A store opened through the library can be given a vector cache of its own:
Semlith::vector_cachetakes acache::Location(a file and a cap), and that store’s index runs read and write that cache and never the machine’s
Changed
semlith cloud statusreports how many chunks the organisation indexed this month against its cap (12,400 of 100,000 chunks indexed) when the host counts chunks;semlith cloud pushstates the host’s estimate (about 1,400 chunks to index) and its--jsonreport carriesestimate_chunks
0.37.0-rc.2
4 October 2026 · Full notes on GitHub
Fixed
- An image whose extension misnames its format - a PNG saved as
.jpg, as image generators and chat apps often save them - is indexed by its bytes
0.37.0-rc.1
4 October 2026 · Full notes on GitHub
Semlith Cloud, from this machine
semlith cloud login [<org>]signs in by a code approved in the browser (the device authorization grant), or with--tokenchecked against the host firstsemlith cloud connect <org>adds the org’s stores as remote stores named<org>/<store>, listed bystats,files,semlith_stats, the Stores page and Search’s picker with aremote · <org>badge, and refused by every write path with a sentence saying why- A search naming a remote store, or none, is one list: remote hits merged with local ones by score under the same
kand budget, each with its badge, revision and lag semlith cloud push <org>/<store> <dir> [--wait] [--prune]sends only the files whose hashes changed, after semlith’s own refusalssemlith cloud sync <store> on|off: per store, off by default, the ledger’s rows (when, client, session, tool, tokens; never the query text) go to the org’s ledger once a minute, at most 1,000 at a timesemlith cloud reportandsemlith cloud replay- Settings › Cloud draws both states; the Ledger page says what is syncing, the Privacy page what leaves the machine and when, the daemon card
· cloud: <org>, andsemlith doctorhas a cloud line
Added
Semlith::index_paths_under,Semlith::index_rest_underandSemlith::undo_run: a run under a control an embedder drives (pause, yield and continue fromIndexReport::pending, stop and undo every slice’swritten), each taking the store’s lock asindex_pathsdoes
Fixed
- An MCP client reached over HTTP is labelled by the
Semlith-Hostheader its stdio proxy sends, never by the ancestry of the daemon serving it - A stopped run’s undo no longer archives the run’s own definitions as symbol history
semlith searchanswers from connected remote stores too, not only the MCP tool and the portalsemlith cloud replaysays once, not twice, that session replay is off for the org- The model cache is created private (0700) when it does not exist yet
- Markdown heading names drop their inline emphasis, code spans and links: a Confluence heading
## **Making purposeful content**was named with its asterisks in search and the graph - A finished run’s history row is written before anything can read the run as finished; a daemon stopped right after “done” could lose it
- With the cloud unreachable, the search summary counts its stores as skipped, not as 0 hits; a remote store the cloud no longer offers says so in Settings › Cloud;
cloud statussizes caps in GB
0.36.0
2 October 2026 · Full notes on GitHub
Search on a store of many repositories
- Search has no graph list
- Every lookup tool can be scoped
- The right repository first, unscoped
- Faster on a large store
- A faster keyword list
What semlith costs an agent
- Eight tools listed, not sixteen
- Caller questions go to the graph tools
- The hook sends document reads to semlith
- The portal says which tools agents are offered
Fixes
- A folder added to a running store is watched from that moment; it used to be indexed once and then not watched until the daemon restarted (#180)
- The portal on Windows no longer reports ERR_CONNECTION_RESET (#181)
- A store deleted while the page was polling is no longer opened again in the moment between leaving the served set and leaving the registry, which recreated and re-indexed it
- The Graph route reads under a 15 s limit and answers 503 naming how to scope it past that, so no request holds a worker for minutes on a very large store (#173)
Inside the indexkeeps each store’s measure until the store changes and measures a store over 20 000 chunks on a thread of its own, so a cold measure no longer competes with every other route (#175)- The accel countdown test measures the gap between its clock and the lane’s and allows for it, so a preempted runner cannot push it out of bounds either way (#177)
Installing
- Releases are attested and the installers check them
0.35.0
2 October 2026 · Full notes on GitHub
The portal, redrawn
- Nine pages in three groups, and a page per store
- A first-run screen and a five-step wizard
- What the older portal had, folded in
- Live without rebuilding
- A large store’s Graph page no longer holds the daemon
- Add sources adds a folder
- Loaders are the loading
Dropped folders resolve to their real path
- A drop on the portal finds the real path, and uploads nothing
- “Index with semlith” in the file manager, when asked
- Safari drops take the real path
From a manual walk
- Read and decided the way people use it
- Index health reads each store once
semlith startandsemlith upgradesay it once and say it right
The portal’s v6 backend
- Stores are made, named and set from the page
- Review decides several files at once
- Index runs are kept
- The ledger can be paused, and a broken chain repaired without a rewrite
- Session replay is on by default
- Airgap can be switched on at runtime, and every outbound connection is counted
- Start at login, one client at a time, and what each tool costs
- Search and brief answers carry what the agent sees
0.34.0
30 September 2026 · Full notes on GitHub
What the documents hold, counted
- Inside the index counts pages, slides and cells
- Older stores are counted on their next index pass without re-embedding
- Inside the index no longer stalls other reads
Model, tokens and cost in the ledger
- Each ledger row can show the model, tokens and cost of the call that made it
- Cost comes from a models.dev price table built into the binary
- Savings figures are priced from the same table
Fixed
- Doctor reads IO CLI’s user-scope registration
- A correct steering hook no longer reads as stale
- The Doctor page colours each Skill & hook part by its state
0.33.1
30 September 2026 · Full notes on GitHub
Search answers on a large multi-repository store
- The graph list’s walk is bounded
- Seeding the walk uses an index
- A failed graph list no longer fails the search
Exact search finds every line ripgrep finds
- A
<in HTML text no longer hides the lines after it - Every file is searched, and every line keeps its number
0.33.0
30 September 2026 · Full notes on GitHub
Twelve clients, each tested every release
semlith setupsupports twelve clients- Upgrading cleans up after them, once
- Zed and Cline are registered by setup
- ChatGPT desktop (the Codex app) is registered by setup
- Every client on macOS, Linux and Windows
- Every retrieval is filed under the app that made it
- A daemon restart no longer breaks connected clients
- Nothing is created for a client that is not installed
Fixed
- Copilot in VS Code refused every chat with semlith enabled
- An upgrade left every client on the old daemon
semlith doctorreported the wrong start time for the daemon- Setup printed the agent key
- The access report filed every proxied session under one store with zero hits
- The ledger chain could fork
- The stdio proxy’s start line
semlith doctorexplains Gemini CLI’s folder trust- Stopping the daemon mid-index printed an ONNX Runtime error
- A test of the Neural Engine compile countdown no longer fails on a slow runner (#166)
0.32.0
29 September 2026 · Full notes on GitHub
Indexing, several times faster on the machine you already have
- An index pass is three stages running at once
- The Neural Engine, on Apple silicon
- A machine-wide vector cache
- A store that answers while it fills
- Everywhere else
- Experimental lanes, built without their hardware
Fixed
- A store built with one of fastembed’s own models no longer has its batches sent to a GPU lane, which runs granite and would have given it vectors from the wrong model
semlith doctor --gpuprintedn/afor a lane that failed its check; it printsFAIL- A pack that fails its digest is deleted whole, not left half-unpacked
- The GPU lane through Core ML was sent batches of one to three chunks on a model that computes eight at a time, so three quarters of its work was padding, and the lane’s pace, read from those batches and charged for the wait of a second batch queued behind the first, cut the next batch further
- The vector cache takes 1.7 KB on disk a vector, where it took 4.7 KB: its table kept about a kilobyte of each row on the row’s page and moved the rest of the vector to an overflow page of its own, so a full cache was three times its cap
semlith statsnames every lane that is on, the Neural Engine and the experimental lanes included; it named only the CPU, the GPU and CUDAsemlith accel statusshows the running daemon’s lanes, so a Neural Engine compiling in the daemon no longer reads as idle in the terminal- A run’s rate counts vectors that have landed, not rows written ahead of them
- The portal’s pages no longer wait seconds on a large store: the Stores figures read how many lines each file spans from a new index on the chunks table instead of every chunk’s text (14 s to 0.2 s on a 600 MB store)
- A daemon stopped while an accelerator lane was restarting no longer waits for the lane: batches queued on a lane that is not ready go to the CPU
- A killed lane worker no longer takes the daemon down with it
- The Neural Engine no longer compiles for minutes on every start or fails its start
0.31.0
28 September 2026 · Full notes on GitHub
A store takes the disk its live content needs
semlith compact- The daemon compacts on its own
- What a store takes is shown
- A reader sees a writer’s new shards
Fixed
- A file refused for a secret it gained left its old text readable in freed database pages, the keyword index and the write-ahead log until a vacuum
- A key pasted as a search query was recorded in full in the ledger
- A model download that stopped receiving bytes left
semlith setupwaiting for ever with no message - A file that a
.semlithignoreor.gitignoreline excluded after it was indexed stayed in the store, searchable, for ever: only a file gone from disk was swept - Machine limits notes ran a reason into the next sentence (“would allow 7 Room up to 8”), and the Stores page’s Saved column broke inside a word
- Three checks that failed intermittently now compare like with like: the native smoke’s pause window follows the run’s measured batch rate (#152), the drive’s
threads eachcheck skips on a home whose value is saved (#153), and the extra-store memory check measures one server answering from one store and then from three, rather than two processes whose footprints settle up to 120 MB apart for the same store (#149)
0.30.1
27 September 2026 · Full notes on GitHub
A long run stops re-checking what it has left, and its estimate moves
- Slices check the files they reach
- The estimate follows the run
Fixed
- The document reader no longer panics on text with a multi-byte character twelve bytes after an
&(“end byte index 12 is not a char boundary”), which it did five times on the rust-lang/book documents - Machine limits states one figure for the vectors per store
- A slice cut short counted the files it had refused as not yet reached, so a run with refused files settled on a total its counter never reached
0.30.0
26 September 2026 · Full notes on GitHub
Agents use semlith, and it answers them well
- What breaks if this changes
- Answers an agent can act on
- Bringing the agent to them
Fixed
- The remaining-time estimate no longer jumps to minutes while a run writes its index, and never more than doubles between polls
a_port_something_already_holds_is_seen_as_heldno longer races the rest of the suite- The daemon’s watcher said
0 indexed at startupfor a catch-up it had only queued; it now says the catch-up was deferred, then what it found semlith startno longer fails while a terminalsemlith indexis writing one of its stores- Across several stores,
briefnames the store on every span and symbol, and a symbol’s edges come from its own store rather than every store defining the name - The server instructions stayed over their 600-byte limit by the length of “folders” when the roots did not all fit
- The research agent reads a located span through
semlith_read;Readis kept for files semlith does not index - A run card’s plan line is updated in place, so a poll no longer rebuilds it
- A run started from the portal shows its time estimate from the first batch: daemon runs now record the store’s embed rate, and a store with none uses the last run the daemon watched
- A
semlith_indexforwarded to the daemon names every refusal of the run, its skips by reason, and how many files await review, as the in-process reply does
0.29.0
25 September 2026 · Full notes on GitHub
Eleven portal fixes found using 0.28.0
- Index run cards count down
- Stores can be deleted together
- Impact says what it shows and where to start
- Graph’s rail keeps its buttons in view
- Smaller fixes
0.28.0
24 September 2026 · Full notes on GitHub
The service indexes 4.6× faster, the GPU works beside the CPU, and the run controls act at once
- Priority now follows the work
- Machine limits apply as soon as they are saved
- Values saved under 0.27.0 take effect now
- Everything the daemon embeds goes through one queue
- Pause and Stop act at the next batch
- Stop can delete the store
- The chunks/s figure is a rolling rate
- Idle sessions are released, and all readers share one query session
- Chunks are batched by length
- The GPU works beside the CPU, on by default
- WebGPU
- CUDA
- Switches
- Where each vector came from
- Lanes are checked before they are trusted
- Only the daemon uses GPU lanes
- A reader panic fails one file, not the store
- The hybrid-core thread count covers Linux and Windows
- Fixed
- Fixed, found while building this release
- The Privacy route lists every download
0.27.0
23 September 2026 · Full notes on GitHub
The portal drawn the way the design draws it, and reports that write themselves
semlith startagainst a store a daemon already holds is no longer an error- Reports schedules itself
- Reports is the page the design specifies
- Two of the builder’s three toggles do what they say
- A fifth report format: PDF
/api/reporttakes a window and a scope- Impact draws the canvas its caption promised
- Index and Inside the index are two pages
- Session replay looks like the design in all three places it appears
- One hover card, everywhere
- One unreadable store no longer takes the readable ones down with it
- Pages scroll to their end
- Controls read as controls
- Two columns become one on a phone
- Every page’s panels are in the design’s order
- Scroll position survives a live repaint
- Code blocks lose the fade
- The type scale is the design’s
- Three layouts that fought the page
- The Stores page notices a root folder that has gone
- A saved limit is called saved on every branch
- About loses two blocks
- The retrieval harness gains an image class
0.26.1
21 September 2026 · Full notes on GitHub
The portal, opened beside the design it was built from
- The first-run screen is complete
- The menu is four groups again
- The routes the design draws between pages are there
- The Graph page’s right column was painting over itself
- Reports is the page the design draws
--model opus_5priced at Sonnet 5 and said so- The browser’s own paragraph margin was a second spacing system
0.26.0
20 September 2026 · Full notes on GitHub
The whole portal, free, in the binary
- Impact
- Trace
- The path finder, drawn
- Map
- Inside the index
- The ledger, session by session
- Session replay
- Reports
- Cloud
Four defects, all of them older than this release
- #122
- #120
- #121
- #124
0.25.0
20 September 2026 · Full notes on GitHub
What was tried, and what was kept
- Code chunks carry their definition
- A cross-encoder writing the order outright
- The same cross-encoder fused with the fused order
- A deeper candidate pool for questions
- Normalising spellings before comparing a hint against a path
0.24.0
19 September 2026 · Full notes on GitHub
0.23.0
19 September 2026 · Full notes on GitHub
An agent asking semlith a question used to spend four round trips on it: search, read the span, ask what calls it, read those. Three of them re-established what the first already found. semlith brief answers it in one.
Retrieval
Fixed
- Warm query p50 and peak indexing memory are measured again
#104closes- The native smoke harness runs only on release pull requests
- sha2 0.11 finalises to a value that no longer implements
LowerHex
Changed
tools/listis thirteen tools at 4 441 bytes, about 1 111 tokens, against twelve at 3 995 and 999semlith statssays whether a store carries the rescoring sidecar and how many definitions it has retired
0.22.0
19 September 2026 · Full notes on GitHub
Retrieval was measured by an instrument that could not measure it. This release rebuilt the instrument first and only then moved the number, which is why the figures below are lower than the ones they replace and mean more.
The measuring stick, before the ranking work
- The retrieval harness indexes a pinned corpus, not the working tree
- The question set is 107 questions, split 77 development / 30 sealed
- Every figure is the median of three runs, with the spread beside it,
- A
pathquestion can be a hit
Retrieval
- An identifier-shaped query puts the definition first
Fixed
- The native smoke harness no longer writes under your own home
- The smoke harness says what supervision it found
- #104 is not fixed
0.21.0
18 September 2026 · Full notes on GitHub
On 2026-09-17 a session opened with no semlith server. The registration was correct, at user scope, and the installed binary answered initialize in well under a second over six stores. It happened again on 2026-09-18. Nothing anywhere said why.
semlith is there before a client asks
semlith start --serviceinstalls the daemon as a login service: a launchd user agent on macOS, a systemd user unit on Linux, a logon task on Windowssemlith setupand the installers install it, including where nothing can answer a prompt — a piped installer, CI,--yes- Installing onto a port something already holds registers the service for the next login and leaves the running daemon alone
- On macOS, a binary inside
~/Documents,~/Desktop,~/Downloadsor iCloud Drive is refused rather than installed
The handshake no longer waits for the embedding model
semlith mcpanswersinitializeandtools/listbefore any model is loaded- A machine with nothing indexed gets a server instead of an exit code
semlith mcpno longer claims a privacy rejection for a file that is not there
semlith doctor names the step that failed
- A server registered at user scope and switched off for one directory is reported as a fault in that directory, naming the file, the key and the directory, with the command that turns it back on
- Every registration semlith writes names the resolved absolute path of the binary rather than the bare command
semlith
Housekeeping
- The native smoke harness on all three platforms installs the login service, kills the daemon and confirms it comes back, and checks that the handshake answers with the embedding model made impossible to load
0.20.2
18 September 2026 · Full notes on GitHub
A full manual drive of every portal page on 2026-09-17 — every button, filter, picker, toggle, sort, index run, search, graph interaction, agent action, privacy scan and about row, at desktop, tablet and phone widths — found 62 defects. This release fixes all of them, and adds the scripted browser drive that replays every one of their reproductions as a standing gate.
The product no longer contradicts itself
- A store holds only what its roots cover
- One search is one retrieval
LAST WRITEis the store’s last write, read from the store rather than from this daemon’s memory of its own sessionsemlith ledgerand the portal both print local time with the zone offset, from the operating system rather than from UTC arithmetic
Index runs tell the truth about what they did
- Runs are keyed by run id rather than by store
- A finished run offers Remove and not Stop
- Live runs sort above finished ones, a finished card folds to one line, all the finished cards can be cleared at once, and the “N runs queued.” line clears when nothing is queued
- The live chunk counter is the run’s, not the slice’s
- A store the portal creates holds its watcher off until the run that is about to index it arrives, so a run no longer finds its own files unchanged and reports
1 indexed … 1 chunksfor a store that has just gained three files - A run that is rewriting its shards says so
Features that did not work
- Adopt existing .semlith
- Add from a URL
- Open in Files
- Projects under a folder…
- The graph’s edge-kind filters filter
- Changing
lang:,path:or the token budget re-runs the search, like every other control on the page - The Retrieval ledger page shows the ledger: the rows
semlith ledgerprints, paged and sortable
The HTTP surface
- An unknown path answers
404, with401kept for a request that failed the token site.webmanifest’s icon paths resolve, so a page load logs no console error/api/files?limit=above the maximum answers400naming it, the same contractoffsetalready had, rather than clamping silently
Copy, states and polish
- A registry entry whose directory is missing is shown as missing, naming the path that is absent, and is offered nowhere a real store is offered
- The Machine limits panel’s derivations are computed from the numbers it prints: a negative headroom says the floor applies, MB and MiB are one unit, “threads each” recomputes when “runs at once” changes, and a saved value is called saved rather than derived
- Doctor gives a fix command only for a client that is on this machine, and where two commands are genuinely right for one state the cell says why
- The Claude Code HTTP stanza carries the
--scope userthe paragraph above it insists on; inline code on the Agents page renders as code; closing the MCP endpoint asks first; and the dry run is the primary button while the one that writes ten configuration files is the secondary - Four model notes described a different model than the row they sat on, the model semlith actually runs showed no size, and sorting by size buried the only rows that had one
- The Privacy page’s Rules badge says it is about new writes, and the scan below it says it is about what is already stored
- The theme control offers system, light and dark, so following the operating system is reachable again
- Truncated paths carry a
title, four tables carry captions, unselectable rows in a picker are dimmed, pickers sort case-insensitively, the code preview fades where a line continues, the tablet stat tiles break three and two, a phone’s store chips are one scrolling row, and a sub-second run reads in tenths - The first search after the daemon starts says it is loading the embedding model rather than showing five seconds of “searching”
The gate
tests/drive/drives Chrome over the DevTools Protocol and replays the reproduction for every one of the 62 findings, asserting the corrected behaviour and writing a transcript and a screenshot per check
Unchanged
- The MCP tool list, the tool schemas and the store format
0.20.1
17 September 2026 · Full notes on GitHub
Fixed
install.ps1can replace a semlith that is already installed
0.20.0
17 September 2026 · Full notes on GitHub
A sliced run carries on instead of starting over
- A run yields the writer back to the watcher every 45 seconds and returns as a fresh job
- The progress a page shows belongs to the run rather than to the slice, so the counter no longer returns to 1 partway through
The run clock
- Starts when the run is submitted, not when the writer reaches it: the wait for a writer is time you are waiting
- Spans every slice
- Stops while a run is held, and freezes at its total when the run ends
The Doctor page
- Has a navigation icon
- Its Clients and Rules sections use the same layout as every other section in the portal
A run lives in the daemon, not in the page that started it
- An index run is the daemon’s: its id, paths, status, counters, clock, the last 500 lines of its log and its closing summary
- The snapshot is written by the same
sayclosure that emits every event, so the card and the log cannot disagree about what happened - The Index page draws one card per store, each with its own Pause, its own Stop and its own log, read by a cursor so two tabs open on the same run each see every line exactly once
POST /api/indexno longer streams- The elapsed clock was measured around one slice
One folder becomes one store
POST /api/indextakes"store": "each"— one store per path, each resolved through the same functionsemlith index <path>resolves through, suffix and all, so indexing a folder from the page and again from a terminal produces one store rather than twosemlith index --eachis the same choice in the terminal, sequential — one process, one embedder, one store at a timesemlith index --projects <FOLDER>takes the paths from the git repositories directly under that folder and implies--each- The Index page has the same list as a checklist, from
GET /api/projectsand the same discovery function, so the page and the terminal cannot disagree about what is under a folder
Runs wait for each other, and the daemon decides how many
- Each store’s writer used to take the next job on its own queue with nothing above it, so eleven open stores meant eleven runs at once whatever the machine had
POST /api/index/controlgainsdequeue, and a queued card’s button reads Remove- A new
src/system.rsreads logical cores, physical cores where the platform says, total memory and memory free now —/proc/meminfo,sysctlandhost_statistics64,GlobalMemoryStatusEx— with no new dependency - The three are settings rather than constants:
SEMLITH_INDEX_PARALLEL(new),SEMLITH_EMBED_THREADSandSEMLITH_INDEX_MEMORYwin, then~/.semlith/settings.json, then the derivation - Changing runs-at-once takes effect on the next admission: raising it admits the head immediately, lowering it stops nothing already going, because a run holds a writer and undoing it would cost the work it has done
- A daemon that ends with runs queued drops them, and its next start names each on that store’s event feed as never started — along with any run that was going and what it had committed
The portal reads live
GET /api/changesreturns six monotonic integers, one per data domain, each bumped in the one function that writes that domain- It is a poll and not a server-sent stream because a stream holds one of the daemon’s eight HTTP workers for as long as the tab is open, which is the same constraint the run-state work above exists to respect
- Search, Read and Graph are not refetched on a timer
Also
- The Doctor page has a navigation icon and the card padding every other page uses
0.19.0
17 September 2026 · Full notes on GitHub
One unreadable file no longer ends the run
- A file that fails on its own content — a truncated PNG, a source file tree-sitter cannot parse — is reported
failedwith the decoder’s or the parser’s own message, and the run indexes the next file - Every skipped file says why, from a closed set:
empty,over 8 MiB,not a regular file,unreadablewith the operating system’s own words,binary,no text in this document,not a decodable image - The
doneevent, the CLI’s last lines andsemlith_index’s return count the skipped by reason and name every failed path - A file whose reader produced nothing used to be counted and never reported, so the portal’s progress bar stopped short of its own total on any tree with binaries in it
- Entries the walk itself cannot read are
failedfiles on the same channel rather than a line on stderr the daemon never sees - The watcher survives a per-file failure
Credentials
- A content scan runs on every file’s text before it is chunked, stored or embedded, including the text a reader produced from a
.docxor a notebook - The deny-list widened to every environment-variable file rather than
.envand.env.*alone, and to the per-user credential files the hidden-file rule used to catch on its own:.npmrc,.netrc,.pypirc,.pgpass,.htpasswd,.boto,.s3cfgand*.ppk - A refused file that an earlier run indexed is evicted in the same pass, and the refusal says so
semlith scan [STORE]runs both rules over everything a store already holds, prints each file semlith would refuse today, and exits non-zero while any remain
A whitelisted dotfile is indexed rather than refused
- The hidden-file rule now applies only to a path the caller named
- This changes what a store holds on a re-index
Fixed
semlith indexfrom a second process whilesemlith startis running produced a store the portal and every agent could not see until the daemon was restartedsemlith_symbolandsemlith_pathreturned Windows verbatim paths —\\?\C:\work\api\src\lock.rs— which no editor opens and no shell completes- The home directory was canonicalised twice per file to answer a question that cannot change during a run, which on Windows is two opened handles per file
Also
semlith_pattern,semlith patternand/api/patterntakepath— the same glob filter every other surface takes, which this one ignored — andoffset, so a listing the 200-match cap cut short can be continued- The portal’s Index page shows the elapsed time, corrected to the daemon’s own clock on every file so a backgrounded tab cannot drift, counting through a pause and frozen on the total when the run ends
0.18.0
16 September 2026 · Full notes on GitHub
Every agent client on the machine, from every project
semlith setupregisters semlith in every client that documents a registration command, at the scope that client spells “every project”, rather than registering Claude Code alone and printing the other twenty-six as stanzas to paste- Every registration is the stdio form: the client launches
semlith mcp, which reads the agent key from~/.semlith/agent.keyitself - An existing semlith entry is removed before the new one is added, at every scope the client has — including the project-scope entry in
~/.claude.jsonthat made semlith invisible from every directory but one semlith setup --register-all, and a control on the portal’s Agents page, write the configuration file of the ten clients that have no registration commanddocs/clients.mdcarries the registration facts in its fence info strings, so the document a human reads and the onesrc/clients.rsparses are one file- The shell startup block
semlith setupwrites carriesPATHand nothing else
semlith doctor
- New command, with
--jsonand--fix - A portal view of the same report, from the same route
The Privacy page can fix what it reports
- Every failing rule carries the command that repairs it, copyable
directory modes,agent key, andmodel cachewhen the cache is your own carry a button as wellprivate addressesgets the manual step and no button- Fixed: the
agent keycheck rendered the same sentence whether the mode was compliant or not, so a key at 0644 read exactly like one at 0600
Fixed
- One corpus indexed twice now produces one index, and the retrieval harness reproduces its own numbers (#88)
SEMLITH_CHECKPOINT_SECSis nowSEMLITH_CHECKPOINT_FILES
0.17.3
16 September 2026 · Full notes on GitHub
Added
- A
## Prior artsection in the README, citing the paper by title, its four authors and its arXiv id, and turbovec by author, licence and repository, with two sentences on what data-oblivious buys a local index tests/readme.rsasserts the README carries both the turbovec repository URL and2504.19874, so an edit that drops either fails the buildtests/portal.rsasserts no semver literal appears in a user-visible string insrc/portal/app.js
Fixed
NOTICEnamed BAAI/bge-small-en-v1.5 as the default model, which the product stopped usingdocs/architecture.md, which the README calls the full account, described the single-file index that store format 2 replaced in 0.7.0 — including a crash-safety argument and an atomic-write argument stated over the wrong object- The portal’s About page said forty grammars arrived in a named release and that the binary had grown by a measured number of MiB against another one — three versions and four figures, hardcoded, where no reader could tell which build they described
A Ctrl-C guarantee that CI can see fail
- The test now waits for the watcher’s own
watching …banner, which is printed after the handler is installed, instead of for a clock .github/smoke.shgainscli/watch/sigint-whole, which interrupts a real watcher and then checks the exit status, that no half-written index was left behind, and that every chunk still has a vector
Removed
- The About page’s
MCP revisionsrow
0.17.2
16 September 2026 · Full notes on GitHub
Added
docs/portal.md, the first documentation of the portal: one section per page, how the daemon starts, and the concepts behind the graph, the search list and the two credentialsdocs/clients.md, holding the client configuration stanzas moved out of the READMEdocs/performance.md, holding the benchmark tables with their reproduction commands and the release each was measured fortests/readme.rs, which parses the counts out of the README and asserts each against its source — languages, edge kinds, tools, commands, formats, image types and clients
Fixed
- The portal’s Graph page drew four of the six edge kinds the store holds:
containsandaliaseswere fetched from/api/graphand dropped before painting, while the hover card counted them anyway src/graph.rs’s module comment still said six languages carry edges, which 0.17.0 made false- Four places said a rotated agent key stays valid until the daemon exits, including the message the portal prints after a rotation
docs/compatibility.md’s covered-surface table named none ofsymbol,neighbors,path,ledgerordrop, which are stable commandsCONTRIBUTING.mdsaid CI runs on Linux and macOS, and did not mention themsrvorscriptsjobs
0.17.1
15 September 2026 · Full notes on GitHub
Ten bugs. Four of them are one bug: Windows sets no HOME, and semlith read it in nine places that each had a different answer when it was missing. The rest are what a person meets on the first day — a path printed in a form nothing opens, a pipe closed early, a root that cannot be read, a forget that removes nothing, a page parameter checked and ignored. No new command, no new tool, no new argument and no schema change.
One home-directory helper
- #70 — the store home resolves on Windows
- #71 — the portal’s directory browser refuses instead of rooting at the drive
- #72 — the directory deny-list fails closed
- #73 — a run with no home is an error, not a store in the working directory
Fixed
- #74 — paths print in the form the platform opens
- #75 —
semlith files | headexits quietly - #76 — an unreadable index root creates nothing and registers nothing
- #77 —
semlith forgetforgets the file the listing printed, andsemlith dropruns at all - #78 —
GET /api/searchapplies the offset it validates
Notes
- Five answers change where the old one reported success
- A Windows user may have a stray
.semlith - #82 — the harness ledger is empty of real rows
- No store format change
0.17.0
15 September 2026 · Full notes on GitHub
The code graph covered six of the forty-six languages --lang accepts. That gap was a promise the product did not keep: --lang kotlin narrowed a search perfectly well, and then semlith symbol answered nothing about the same corpus with nothing saying why. It is closed.
One language table
- The extractor reads
filter::LANGUAGES, the table the search filter reads - Every language has a fixture that says what it must extract
Forty grammars
- Twelve of the new grammars ship a tags query; twenty-eight do not
- Nothing is vendored and nothing is a git dependency
THIRD-PARTY-NOTICESships with the crate and with every release archive,
What a symbol is in a language that has no functions
- Fourteen of the forty-six are markup, data or configuration, and their structure is their symbol set
- What they reference is files
- Svelte and Vue contribute their template and say so
Fixed
- C and C++ attributed every call to the file rather than to the function making it
- C++ captured no calls at all, C# captured no invocations, JavaScript captured no imports, PHP captured neither a require nor a function call, and Swift captured no calls
- Elm recorded nothing about a declaration depending on another
Surface
semlith languagesprints agraphcolumn,- No new command, tool, argument or schema
What it costs
- The binary more than doubles: 47.0 MiB to 111.3 MiB, +64.3 MiB (+137%)
- Retrieval moved, and the move was measured rather than assumed
0.16.0
14 September 2026 · Full notes on GitHub
0.15.0 made the free product honest and cheap. It did not make it better at finding things. This release spends the harness that release built on the ranking itself, and reports what the harness said — including where it said no.
The graph list stops being a set and becomes a ranking
- Graph neighbours are ranked by personalised PageRank
- A symbol question is answered with one evidence block
- An edge records the line the call was written on
- A walk crosses a re-export
Search reads the query before it ranks the answer
- An identifier and a question are weighted differently
prefer: code | docs | any- The fused set is reranked by graph distance and freshness
Two new tools, and a tool list that did not grow
semlith readsemlith pattern- Twelve tools now fit the budget ten used to
A store has one name
- The portal drew store chips the search route then refused
The portal
- Neither new tool gets a page, and that is the decision rather than an omission
- The Search page rebuilt to that design: the query-shape hint, file cards with span summaries, word-pill fusion badges, the provenance sentence, a signature strip, a line-number gutter, a read-whole-symbol control, and an ego-graph panel
- Three bugs found by rendering the pages rather than reading the diff: image previews were handed a
blob:URL the page’s own CSP had always refused and so had never worked; the Read and Pattern views could let a slow earlier answer overwrite a newer one; and the graph canvas leaked an animation loop per visit - The Languages page is gone
0.15.0
14 September 2026 · Full notes on GitHub
The graph stops answering questions it cannot support, the search stops sending the thing itself when it was asked where the thing is, and the ledger starts recording the agents it exists to measure.
A graph that says how much it knows
- An edge’s target is resolved, not matched by name
edges.hintrecords what the source said about where a call goes- A path walks definitions, not names
--all-edgeswalks the old way and says what it foundsemlith neighborscollapses and hides- Search expansion follows only the kinds that mean “depends on”
A search that answers where
semlith_searchanswers with locations by default- Every hit says whether its file has moved under it
tools/listis 3 940 bytes with one store open, from 8 634
A ledger that records the user it exists for
- Every retrieval is recorded, from every surface
- Recording is on by default, and
semlith start --ledgeris removed - Both sides of a ratio are counted with the store’s own tokenizer
semlith ledger --verifyre-walks the chain- Four nullable columns on
retrievals
A number behind every retrieval claim
tests/retrieval.rs
Removed
semlith start --ledger- This is a break in the covered surface
Notes
- Existing stores open unchanged, and
format_versionstays 2
0.14.0
14 September 2026 · Full notes on GitHub
Every finding of the security audit of 0.13.0, closed in one release, each with the test that would have caught it. The restrictions are the release: docs/compatibility.md records the four that break something 0.13.0 did, with the way back for each, and docs/security.md is the user-facing version of what semlith now refuses.
Nothing else on this machine can act as you
- H2, L6 — the portal session moved from a cookie to a request header
- M1 — the token comes from the OS random source
- M9 — a panicking route costs one request
- L1 — what one client can hold is bounded
- L2 — an
Mcp-Session-Idfrom a client is accepted only as the sixteen hex characters the server produces
Nothing you did not write decides what semlith answers with
- M2 — a store semlith did not create is opened only after
semlith trust - M7 — the model weights are pinned to a commit and a digest
- L3 — the parsers are bounded
- L4 —
/api/imagecanonicalises before it looks up
What a leaked agent key gets
- M6 — the agent-facing index tools work inside a boundary
- M6 —
semlith addrefuses an address that is not on the public internet - M4 — the agent key stops travelling
On disk
- M5 — what semlith writes is readable by its owner and nobody else
- M3 — the PATH line
semlith setupwrites is a shell word - L5 — the registry’s temp file carries this process’s id
The release itself
- #57 — the prebuilt Linux binary starts on Debian 12, Ubuntu 22.04 LTS, RHEL 9 and Amazon Linux 2023 again
- H1b —
semlith upgradehas one origin and no way to be told another - H1c, H1d — the download is bounded and the archive is unpacked in this process
- M8 —
release.ymlgrantscontents: writeto the one job that uploads - L7 —
install.ps1sets TLS 1.2 before its first request - I1, I2, I3 —
SECURITY.mddescribes the release that exists
Added
semlith trust <dir>records a store outside the store home as one you have agreed to open, andsemlith trust --listprints what is trustedsemlith index --include-secretsindexes what the deny-list otherwise refuses- The portal’s Privacy page carries a Rules section: one row per rule this release adds, each with the daemon’s own check of it
docs/security.md, the user-facing version of what semlith refuses, anddocs/models.md, the pinned commits and digests with the commands to check them yourself
0.13.0
13 September 2026 · Full notes on GitHub
The portal becomes the product’s own design, agents get an endpoint they can keep in a config file, and a query can find a picture.
Added
- MCP over HTTP, at
http://127.0.0.1:7365/mcp - A persisted agent key, in
~/.semlith/agent.key semlith key showandsemlith key rotate- A rotation carries the key into the files that hold it
- Bulk forget, and deleting a store
- An index run says what it is doing
- A request no longer waits for the watcher
- Pause and stop an index run
- An endpoint switch
- Image search
- Sorting and pagination on every table the portal renders
- An
indexedcolumn on the Files page
Changed
- The portal is rebuilt against its design
- The product is written “Semlith” in prose
- The Linux prebuilt binaries print their glibc floor
initialize,tools/listandpinganswer with no store open
Removed
semlith impact, thesemlith_impactMCP tool andGET /api/impact- This is a break in the agent-facing surface
Fixed
- A tooltip inside a table was unreadable
- The Index page painted an empty bordered box
--airgapcould have fetched a model- A route that no longer exists answers 404
- The install script’s progress bar, properly this time
0.12.0
13 September 2026 · Full notes on GitHub
The store learns the shape of the code in it, and search uses it.
Added
- A code graph, extracted on the same pass that re-embeds a file
- Extracted or inferred, on every edge
semlith symbol,semlith neighbors,semlith path,semlith impact- Graph-aware search
- A Graph page and an Impact page in the portal
- An opt-in retrieval ledger
Fixed
- The install script’s progress bar
Notes
- Existing stores open unchanged
- Measured
- Six languages carry edges
- Everything in this release is free on every tier, permanently
0.11.0
12 September 2026 · Full notes on GitHub
The rest of a real archive, and a way to put something into a store that was never a file on the disk.
Added
- EPUB, RTF,
.emland.mboxreaders semlith add <URL>- Twenty-one more languages for
--lang - A Languages view in the portal
Changed
- The portal’s Files view shows a language for a file that has no extension, where it previously showed nothing
Security
semlith addis the first outbound connection semlith makes that is not the model download orsemlith upgrade, and it holds to the same rules
0.10.0
12 September 2026 · Full notes on GitHub
One command on a fresh machine. No Rust toolchain, no package manager, nothing installed first — and on Linux, no OpenBLAS and no OpenSSL either, because the binary no longer needs them.
Added
install.shandinstall.ps1semlith setup [--yes]semlith upgrade [--check] [--version <tag>] [--airgap]- Portal parity
Changed
- The Linux binary needs nothing but glibc and libstdc++
- The OpenBLAS instruction is gone
- The README’s Install section leads with the two one-liners
- One new runtime crate
Documentation
docs/compatibility.mdnow covers the install script URLs and the environment variables they honour, the release archive layout both they andsemlith upgraderead,semlith setup --yes, andsemlith upgrade --check’s exit codes
0.9.0
12 September 2026 · Full notes on GitHub
A store no longer has to live inside the repository it indexes, and a portal in your browser shows you what is in it. semlith start is one process that owns every store, keeps them current as you save, and serves that page on 127.0.0.1 — which also ends the choice between a watcher keeping a store current and an agent being able to write to it.
Added
- A store home
semlith adopt <dir>semlith start- The portal
semlith mcpforwards to a running daemon--airgap- A token rotate route
Changed
- Client stanzas lost their paths
semlith mcpwith no flags opens every registered store rather than./.semlithalone- The out-of-scope note in
AGENTS.mdanddocs/architecture.mdnow states the loopback rule instead of forbidding a server, per #41 turbovec0.9.0 → 1.0.0:search_with_allowlistreturns aResultinstead of panicking on an id the index does not hold, which is the better contract for a shard that legitimately lacks an id its range coversfastembed6.0.1 → 6.0.3- Three further Dependabot updates that landed on
developwhile this release was in flight and are merged into it rather than shipped separately: a patch-updates group of two crates,Swatinem/rust-cachein both workflows, andsoftprops/action-gh-release3.0.2 → 3.0.3 chacha20in the lockfile, which had been yanked upstream
Security
- The portal binds
127.0.0.1only, with no flag to change it
Dependencies
- No new crate
0.8.0
30 July 2026 · Full notes on GitHub
The documents a corpus is actually made of. A notebook, a Word file, a slide deck, a spreadsheet or an HTML page is now read as the text a person opening it would see, rather than as its markup, its JSON, or not at all.
Added
- Nine more formats, behind the same extraction the PDF reader already sat behind
- A cap on what an archive may decompress to: 32 MiB of text
zip8.6.0
Changed
- HTML files and notebooks are indexed differently than before, not just additionally
- A document that cannot be read is a skipped file
- No store format change and no migration
0.7.0
30 July 2026 · Full notes on GitHub
A corpus larger than a repository. The first index of one says where it has got to, survives being interrupted, and searching it costs a bounded amount of memory rather than an amount that grows with the corpus.
Changed
- Breaking: a store created by 0.7.0 has a new layout, and an older semlith will not read it
Added
- A resident-memory budget for the vector index
- Checkpointed indexing
- Progress that predicts
- Opening a store loads no vectors
Performance
- Changing one file in a sharded store rewrites one shard rather than the whole index — the difference between watching a monorepo and not being able to
- Search latency is unchanged for a store that fits inside its budget
0.6.0
30 July 2026 · Full notes on GitHub
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
Added
- MCP
2026-07-28, the stateless revision, alongside the handshake - Three more tools, so the MCP surface covers what the CLI does
- A setup stanza for every MCP client in common use
docs/compatibility.mdformat_versionin the store’s meta tableSEMLITH_MCP_INDEX_BUDGET- The MCP server says what it is on stderr
Changed
semlith forgettakes the store’s write lock
Performance
- 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
- An MCP server at rest holds no store lock:
semlith indexin another terminal against the store an open server is serving succeeds
0.5.0
30 July 2026 · Full notes on GitHub
One query across several stores, so an agent working across repositories asks one question instead of one per repository.
Added
--storeis repeatable on the read commands- Every hit says which store it came from
SEMLITH_STOREaccepts a list- One MCP server, several stores
Changed
- A read command refuses a store path that is not already a store
index,watchandforgettake exactly one--store
0.4.0
29 July 2026 · Full notes on GitHub
Keeps a store current while you work: files are re-embedded as they are saved, and an agent already connected over MCP sees the change without restarting.
Added
semlith watch [PATHS...]- A long-running reader now sees another process’s writes
- Ctrl-C stops a watcher cleanly
Changed
semlith watchholds the store’s write lock for as long as it runs- An indexing pass that changes nothing no longer rewrites
index.tv
0.3.0
29 July 2026 · Full notes on GitHub
Narrows a search to part of a corpus, so one store per repository can answer a question about one subsystem.
Added
--path,--extand--langonsemlith search- The
semlith_searchMCP tool takes the same filters semlith languages
0.2.0
29 July 2026 · Full notes on GitHub
Removes three of the four limitations 0.1.0 shipped with, cuts peak indexing memory to a third, and changes the default embedding model.
Changed
- New default embedding model:
granite-embedding-small-english-r2, int8 - Existing stores are not affected and are not migrated
- Search is now hybrid
- ONNX Runtime thread count is chosen rather than defaulted
- Minimum supported Rust version is now 1.89
Added
- One writer per store
semlith modelslists the new default alongside fastembed’s built-in models
Fixed
- A release whose git tag disagrees with
Cargo.tomlnow fails the release build instead of publishing binaries labelled with a version they were not built from
Performance
- Peak indexing memory is now roughly 600 MB and no longer grows with the corpus
- Indexing throughput is up from ~13 to ~23 chunks/sec
- Retrieval quality
Library API
DEFAULT_MODEL: EmbeddingModelis replaced bydefault_model() -> ModelSemlith::opentakesOption<Model>rather thanOption<EmbeddingModel>, andSemlith::modelreturns&Model- New modules:
embed(model identity and loading) andlock(store locking)
0.1.0
26 July 2026 · Full notes on GitHub
First release.
Added
- Local semantic search over files
- turbovec-backed vector index
- SQLite for everything else
- Incremental indexing
- MCP server
- PDF support
- Sensible skipping
- Commands
- Model selection
Performance
- Warm query: ~6 ms
- Cold CLI start: ~250 ms, almost all of it loading the ONNX model
- Indexing: ~13 chunks/sec, ~1.7 GB peak RSS
- Re-index with nothing changed: 17 ms