Download Latest Version semlith-v0.51.1-x86_64-pc-windows-msvc.zip (24.5 MB)
Home / v0.40.0
Name Modified Size InfoDownloads / Week
Parent folder
install.ps1 2026-10-15 12.7 kB
install.sh 2026-10-15 10.8 kB
semlith-v0.40.0-aarch64-apple-darwin.tar.gz 2026-10-15 25.9 MB
semlith-v0.40.0-aarch64-apple-darwin.tar.gz.sig 2026-10-15 294 Bytes
semlith-v0.40.0-aarch64-unknown-linux-gnu.tar.gz 2026-10-15 25.5 MB
semlith-v0.40.0-aarch64-unknown-linux-gnu.tar.gz.sig 2026-10-15 294 Bytes
semlith-v0.40.0-x86_64-pc-windows-msvc.zip 2026-10-15 23.6 MB
semlith-v0.40.0-x86_64-pc-windows-msvc.zip.sig 2026-10-15 294 Bytes
semlith-v0.40.0-x86_64-unknown-linux-gnu.tar.gz 2026-10-15 26.7 MB
semlith-v0.40.0-x86_64-unknown-linux-gnu.tar.gz.sig 2026-10-15 294 Bytes
SHA256SUMS 2026-10-15 603 Bytes
SHA256SUMS.sig 2026-10-15 294 Bytes
README.md 2026-10-15 7.1 kB
Semlith 0.40.0 source code.tar.gz 2026-10-15 8.5 MB
Semlith 0.40.0 source code.zip 2026-10-15 8.8 MB
Totals: 15 Items   119.1 MB 0

Security

From the security audit of 0.39.0 (2026-10-14): one High and eight Medium findings, each closed with a test in tests/security.rs that failed on the v0.39.0 binary first.

A file can no longer crash semlith (S01, High). A 606-byte Markdown file of nested blockquotes aborted the process through a C assertion in tree-sitter-md's external scanner (parser.c:409, length <= 1024), which no catch_unwind can catch; tree-sitter-yaml has the same assertion, and nested lists and block sequences reach it too. Under launchd or systemd the daemon then crash-looped for as long as the file sat in a watched folder. Every reader of a file's own bytes - the grammars, PDF, Office, mail, notebooks, an image decode check - now runs in a parse worker, semlith __parse-worker, pooled, with a deadline and a memory limit. A crash costs one worker; the file is refused with the reason (new class crashed, in semlith refused, the portal's Decisions as parser crashed with Try again, and doctor), and a per-store poison journal keeps that version of the file refused across restarts. Markdown and YAML get at most 128 levels of nesting (both abort at about 260, measured), past which a file keeps its text and loses its outline.

Agent keys are read-only by default (S03). tools/call answered tools tools/list hid, so any key could add, index and forget. A key now carries a scope: read (the default, and what every existing key becomes) may call only the read tools; write tools answer a refusal naming the fix and leave a ledger row. semlith key --scope write, or the Agents page's Allow writes, grants them. The same rule holds over /mcp, the stdio proxy and a local semlith mcp; the portal keeps the owner's rights.

One slow call no longer stalls every agent (S02). semlith_add, semlith_index and semlith_forget held the daemon's MCP lock for as long as the writer took - a slow URL, a long run - and every other agent, then the proxies' heartbeats, then the portal waited behind it. They are answered outside that lock now, notifications before any lock, a forwarded index says after the index budget that its run goes on in the background, and the add and prices fetches have connect and overall deadlines.

read never serves what a link points at (S05, S13). The stale-span fallback re-read a file with std::fs::read, so a file swapped for a symbolic link after indexing served its target. Files are opened once without following a link and without blocking on a FIFO, checked to be regular on the handle, and read through a cap, for indexing and for the fallback; a path that no longer resolves to itself is reported as replaced and not read.

cloud login opens only the host's own page (S04). The server-sent verification_uri_complete went to cmd /C start on Windows and open / xdg-open elsewhere, unchecked. It is opened only when it is a plain URL on the configured host, printed otherwise, through rundll32 on Windows, and every string the host sends is stripped of terminal control characters.

A repository's config runs nothing (S07). git log obeyed the indexed repository's own .git/config, so log.showSignature and gpg.program could run a program. Every git call ignores the system config and switches off fsmonitor, hooks, gpg and signature display.

llama-server's key is off the command line (S08). It was in argv, where ps shows it, and the port was picked, released and trusted on any /health

  1. The key goes through LLAMA_API_KEY, the server binds a port itself and is reached on the one its own startup line names, and native-smoke fails on a key in any process's command line.

Config rewrites keep modes and links (S09). Rewriting a client config, hook, rules or shell rc file replaced a symbolic link with a file and reset a 0600 file to the umask default. One writer now writes through the link to its target, keeps the exact mode, and creates new files 0600.

A refused secret leaves nothing behind (S10). A file refused for a secret it held after it was indexed had its rows deleted, but its keyword terms, its exact.f32 vectors and its vector-cache entries stayed. All three go in the same run, FTS5 runs with secure delete, and the store is vacuumed.

Releases are signed (S06). semlith upgrade trusted a SHA256SUMS fetched from the same release as the archive, so whoever could replace release assets could replace both. Every archive and SHA256SUMS is now signed by the release workflow with the project's ed25519 key (OpenSSH SSHSIG, as a .sig beside each). upgrade verifies it with the key built into the binary before anything is written; install.sh and install.ps1 verify it with ssh-keygen -Y verify before the checksum; all three fail closed. semlith --version names the key on a second line. Break: the new installers and upgrade cannot install v0.39.0 or earlier, which are unsigned.

Idle sockets no longer lock anyone out (S11). Thirty-two connections that sent nothing filled every slot and the next request, the token holder's included, got 503. The request head is read on its connection's own thread, with a 10 s deadline and a 16 KiB cap (408, 431), and idle connections are capped at eight per address and 48 in all, the oldest silent one closed first.

cargo audit on every push. A new CI job checks the dependency tree against the RustSec database. rustls moves to 0.23.46 for RUSTSEC-2026-0346 to 0349, published after the audit.

Fixed

Three index-time races. A file deleted after its read and before its rows landed stayed in the store as a ghost path; it is evicted when the run ends. Stopping a run dropped every event queued behind it under its roots, deletions included; deletions are now applied. An edit that kept the size and landed between a file's read and its row's write read as fresh, because freshness compared the mtime with the insert time; the mtime the read saw is kept (files.read_mtime, additive) and must match.

Decisions shows a retried file's outcome without a reload. The page refreshes the refusals when a run ends.

Install

macOS and Linux

:::sh
curl --proto '=https' --tlsv1.2 -fsSL https://raw.githubusercontent.com/semlith/semlith/main/install.sh | sh

Windows

:::powershell
irm https://raw.githubusercontent.com/semlith/semlith/main/install.ps1 | iex

Or download the archive for your platform below, unpack it, and put semlith on your PATH. Intel macOS has no prebuilt binary: ONNX Runtime no longer publishes x86_64 macOS builds.

Verify a download against SHA256SUMS before running it, SHA256SUMS against its signature (release key SHA256:a5oJmrakIwDHEWTDWqWe51Ttt6m2tQ0dsGzIqyxDuxs) with echo "semlith-release ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICMTHiHMzeSHzzc+8UDZHUzJcvb6XGUBb+TJdFes91xm" > allowed_signers and ssh-keygen -Y verify -f allowed_signers -I semlith-release -n file -s SHA256SUMS.sig < SHA256SUMS, and its provenance with gh attestation verify <file> --repo semlith/semlith.

Source: README.md, updated 2026-10-15