Releases: simonsysun/seeklink
SeekLink v0.7.0
v0.7.0 adds an optional read-only Model Context Protocol (MCP) stdio adapter for local Markdown vault retrieval.
Highlights:
- Install with
pip install "seeklink[mcp]"oruv tool install "seeklink[mcp]". - Run
seeklink mcp --vault PATHto exposesearch,get,status, anddoctorto MCP clients such as Claude Code, Cursor, and VS Code. - MCP search uses the same retrieval path as the CLI, with compact text summaries and ranked previews in structured content.
- Local stdio only: one server per vault, read-only, no index/write/HTTP/OAuth surface.
Changelog: https://github.com/simonsysun/seeklink/blob/v0.7.0/CHANGELOG.md#070---2026-05-06
Full diff: v0.6.1...v0.7.0
SeekLink v0.6.1
SeekLink v0.6.1
SeekLink v0.6.1 is a small daemon lifecycle and documentation release.
Highlights
- Added public daemon controls:
seeklink daemon statusseeklink daemon stopseeklink daemon restartseeklink daemon pid
- Added
SEEKLINK_DAEMON_IDLE_TIMEOUT.- Default: 900 seconds / 15 minutes.
- Set
0,off,false, ornoto keep the warm daemon running until stopped.
- Added daemon visibility to
seeklink doctor --json, including running state,
PID, socket, vault, models, idle timeout, and best-effort resident memory. - Clarified README, README.zh, and
llms.txtso users and agents can understand
why a localPythonprocess may remain after search, how to inspect it, how
to stop it, and how to bypass it with one-shot commands.
Why This Release Exists
SeekLink uses a local Unix-socket daemon as a warm model cache for repeated
searches. This is useful for latency, but in v0.6.0 it was not visible or
stoppable enough for users who noticed a resident Python process on macOS.
v0.6.1 keeps the warm-search path while making the daemon explicit, bounded, and
easy to release from memory.
Compatibility
- Search ranking and indexing behavior are unchanged.
- Existing one-shot controls still work:
seeklink search "query" --no-daemonSEEKLINK_NO_DAEMON=1 seeklink search "query"seeklink search "query" --vault PATH
- Existing
seeklink daemon --vault PATHbehavior remains available; the clearer
spelling is nowseeklink daemon run --vault PATH.
Verification
uv run pytest -qgit diff --check- CLI smoke for
daemon status,daemon restart,daemon pid,daemon stop,
doctor --json,status --json,search --json, andget -C uv builduvx twine check dist/seeklink-0.6.1*- Isolated wheel CLI smoke with
uvx --from dist/seeklink-0.6.1-py3-none-any.whl
Full changelog: https://github.com/simonsysun/seeklink/blob/main/CHANGELOG.md
v0.6.0
SeekLink v0.6.0 focuses on scoped retrieval correctness, agent reliability, and optional Apple Silicon reranker latency.
Highlights
- Better folder/tag filtered semantic search: filtered searches now request enough vector candidates for narrow scopes, so relevant notes are not lost behind unfiltered distractors.
- New
seeklink doctorandseeklink doctor --jsonfor lightweight environment and index diagnostics. - New
--no-daemonandSEEKLINK_NO_DAEMON=1for deterministic cold-start behavior in scripts and agents. - Improved optional MLX Qwen3 reranker path:
--rerank-k autonow uses 5/10/20 candidate budgets by query shape, and supported MLX model objects use a lighter two-token scoring path with legacy fallback. - Better agent discoverability: README setup snippets,
llms.txtguidance, and PyPI keywords now make SeekLink easier for agents and humans to find and use.
Verification
- Python 3.11, 3.12, 3.13, and 3.14 GitHub Actions matrix passed on the release commit.
- Local test suite:
336 passed. - Package checks:
uv buildandtwine checkpassed. - Bundled release fixtures:
- 22-query fixture with optional MLX reranker active: Recall@10 0.985, MRR 0.977, nDCG@10 0.902.
- 8-query filtered fixture with reranking disabled: Recall@10 1.000, Answerable@10 1.000.
Notes
- MLX reranking is optional. Install with
seeklink[mlx]on Apple Silicon; otherwise SeekLink falls back to first-stage hybrid RRF ranking. - SeekLink requires Python's
sqlite3module to be linked against SQLite 3.45+ with FTS5. - No cloud service or API key is required.
SeekLink v0.5.0
SeekLink v0.5.0
SeekLink v0.5.0 hardens indexing, CJK retrieval, agent contracts, and release packaging while keeping the local-first CLI workflow unchanged.
Highlights
- Safer indexes: SeekLink now records embedder model, vector dimension, distance metric, and chunker version, then refuses searches when the active configuration no longer matches the stored vector index.
- Better CJK query handling: Chinese question-style queries can use the BM25 channel more reliably, including on SQLite trigram fallback builds.
- More predictable indexing: full-vault
seeklink indexreports progress on stderr and keeps the finalDone:summary on stdout, including theSEEKLINK_VAULTdaily-use path. - Better PKM defaults:
todo/andarchive/are no longer hard-skipped during full-vault indexing. - Clearer Apple Silicon reranking: MLX reranking is now an optional extra, installable with
seeklink[mlx]; base installs fall back to first-stage hybrid RRF ranking when MLX is unavailable. - Stronger release safety: the PyPI publish workflow now runs tests, validates tag/version alignment, and checks built distributions before publishing.
For Agents
search --jsonandstatus --jsonremain the structured CLI surface.get PATH:LINE -C Nremains a direct filesystem read for precise context windows.- Full-vault index progress stays on stderr so stdout stays parseable.
llms.txtnow documents optional reranker installation, first-run/model-download caveats, and the SQLite runtime requirement.
Upgrade Notes
- Run
seeklink indexonce for each vault after upgrading so v0.5 can write index metadata and rebuild derived index contents if needed. - SeekLink requires Python's
sqlite3module to be linked against SQLite 3.45+ with FTS5. - Apple Silicon users who want local MLX reranking should install:
uv tool install "seeklink[mlx]"
# or
pip install "seeklink[mlx]"Bundled Fixture Result
On the bundled 22-query fixture with optional MLX reranking active, config A reports:
- Recall@10: 0.985
- MRR: 0.977
- nDCG@10: 0.901
This is a small bundled fixture, not a broad benchmark. Latency depends on hardware, current system load, and whether reranking is active.
Not Included
This release does not change the default embedder model, add cloud APIs, add MCP back into core, replace SQLite, or add GUI/Obsidian-plugin behavior.
Full changelog: https://github.com/simonsysun/seeklink/blob/main/CHANGELOG.md#050---2026-05-04
v0.4.0
Why this release matters
v0.4.0 focuses on making SeekLink easier to trust in real local PKM and agent workflows: structured CLI output, safer reranking, better filtered retrieval, cleaner release artifacts, and stronger evaluation. The default text output and local-first contract stay unchanged.
For the complete change list, see CHANGELOG.md.
| Area | v0.3.2 | v0.4.0 | Practical effect |
|---|---|---|---|
| Agent output | Stable text output; socket JSON for hot loops | Adds search --json and status --json |
Agents can use structured stdout without scraping human text or implementing the socket protocol. |
| Context reads | get PATH:LINE -l N reads forward from a hit |
Adds get PATH:LINE -C N |
Agents and humans can read lines before and after a match, which is usually the useful context window. |
| Reranker control | Fixed reranking behavior for normal searches | Adds --rerank-k N, --rerank-k auto, and --no-rerank |
Callers can trade precision for latency per query instead of changing global model settings. |
| Source metadata | Titles and aliases help source lookup | Markdown headings are indexed as source metadata too | Section-name queries can find the right note even when the body text is sparse. |
| Filtered search | Global candidates could dominate before tag/folder filtering | BM25 and source-metadata candidates are ranked inside the requested scope | Filtered searches are less likely to drop relevant notes because unrelated global hits filled the candidate pool. |
| Exact lookup safety | Reranker could still demote a clear metadata hit in edge cases | Exact title, alias, and heading lookups keep the source-metadata winner at rank 1 | “Find this note / section” queries behave like lookup, not only semantic search. |
| Daemon mismatch | Config mismatch fell back to cold-start repeatedly | search and index auto-restart stale daemons |
Switching vaults or model settings is less confusing and avoids repeated slow fallback. |
| Indexing | Full-vault indexing embedded chunks file by file | Full-vault indexing embeds length-sorted batches | First-run indexing is more efficient while preserving the existing SQLite schema. |
| Evaluation | Public fixture tracked Recall@10, MRR, latency | Adds nDCG@10, Precision@5, MAP@10, reranker metadata, and channel diagnostics | Search changes are easier to judge and debug before release. |
Measured release signal
These numbers compare committed public result snapshots from the bundled 22-query fixture. They are useful release signals, not a broad hardware benchmark and not a freshly rerun historical A/B test on the same machine.
| Metric | Previous public snapshot | v0.4.0 public snapshot | Read as |
|---|---|---|---|
| Source file | A_v0.3.json |
A_v0.4.json |
Exact committed artifacts compared here. |
| Recall@10 | 0.958 | 0.985 | Slightly better coverage on the bundled queries. |
| MRR | 0.977 | 0.977 | Top-hit quality held while the search/eval stack changed. |
| nDCG@10 | Not recorded | 0.901 | New graded top-10 quality signal for future comparisons. |
| p95 latency | 1967 ms | 2124 ms | Same rough local-reranker range; v0.4 adds per-query controls when latency matters. |
Added
seeklink search --jsonandseeklink status --jsonfor agent-friendly structured output.seeklink get PATH:LINE -C Nfor grep-style context windows around hits.- Per-query reranker controls:
--rerank-k N,--rerank-k auto, and--no-rerank. - Markdown heading metadata in source-level search, alongside note titles and frontmatter aliases.
Changed
- Full-vault indexing embeds chunks in length-sorted batches for better first-run throughput.
- MLX reranking caps each passage to the first 200 tokens before scoring.
seeklink searchnow defaults to--rerank-k auto.- Existing indexes migrate to schema v3 and mark sources unprocessed so the next
seeklink indexpopulates heading metadata.
Fixed
- Avoids
sqliteftscrashes on Python builds with hidden static SQLite symbols by falling back to SQLite's built-in trigram tokenizer. - Filtered searches now rank BM25 and source-metadata candidates inside the requested tag/folder scope.
- Exact title, alias, and heading lookups keep the source-metadata winner at rank 1 after reranking.
--rerank-k Nnow really limits cross-encoder candidates even whenN < --top-k.searchandindexauto-restart a stale daemon when vault/model config changes.
v0.3.2
pip install --upgrade seeklink
Highlights
Title-gated rerank blending
When the title / alias channel produces a confident match, SeekLink preserves that source at rank 1 through a blended score so exact-title queries (Zettelkasten, RRF, 遗忘曲线, [[alias]]) aren't demoted by a content-focused reranker. When no title signal is present, the reranker takes over fully and can correct poor first-stage ordering.
On the bundled 22-query pilot (tests/blind/): mean MRR 0.932 → 0.977, mean Recall@10 unchanged, no per-query regressions. Sample size is a pilot, not a statistically powered benchmark.
Line-range retrieval
searchresults are anchored to specific line ranges. CLI printsSCORE PATH:LINE TITLE.- New command:
seeklink get PATH[:LINE] [-l N]reads a window straight from disk — no DB lookup, no daemon round-trip, universal-newline translation, path-escape rejection. - Designed for agents that find-then-read without slurping whole files.
Cold-start reranker parity
seeklink search --vault PATH now uses the same reranker as the daemon path. Before this change the same query could return different rankings depending on daemon state — a silent correctness bug.
Agent-first docs
For agents section in the README and a rewritten llms.txt document the output contract, exit codes, and query-shape expectations for LLM-driven callers.
Compatibility
No breaking API changes. SearchResult gains line_start and line_end fields with default 0.
Supersedes
This release supersedes the same-day 0.3.0 and 0.3.1 tags, which shipped the same code but with inaccurate README content. If you are pinning a version, pin to 0.3.2.
See the CHANGELOG for the full entry.
v0.2.2 — first PyPI release of the daemon-auto-spawn line
TL;DR — Same functional improvements as v0.2.1 (daemon auto-spawn finally works; vault and model guards prevent stale-daemon silent wrongness; PyPI metadata / README / llms.txt polish), but this one actually made it to PyPI. Use pip install seeklink==0.2.2 — seeklink==0.2.1 is not on PyPI.
Why v0.2.2 and not v0.2.1?
v0.2.1's pyproject.toml declared the license twice — once as the SPDX expression license = "MIT" and once as the legacy License :: OSI Approved :: MIT License classifier — which modern setuptools rejects under PEP 639. The tag and GitHub release shipped, but the PyPI build failed. v0.2.2 removes the duplicate classifier (re-fixing what commit c0d261a did historically) and carries an inline comment pinning the lesson.
No functional diff from v0.2.1 — same daemon-first dispatch, same vault/model guards, same CLI behavior. Only pyproject.toml and CHANGELOG.md changed.
All user-facing improvements since v0.2.0
(Copied from the v0.2.1 notes, which are now superseded by this release.)
- Daemon auto-spawn actually works.
seeklink search/seeklink indexwithout--vaultauto-spawn the resident daemon and serve subsequent calls in ~10ms. - Vault- and model-safe daemon reuse. A stale daemon bound to a different vault / embedder / reranker is rejected via a preflight
statusprobe, so switchingSEEKLINK_VAULTorSEEKLINK_EMBEDDER_MODELno longer silently returns results from the wrong DB. On non-Apple-Silicon wheremlx_lmcan't load, the daemon's self-disabled reranker is accepted so the daemon-first workflow still works there. seeklink statusstays cold-start. It never embeds or reranks, so routing it through the daemon was wasting up to a 700 MB MLX reranker download on first run just to print a few numbers. Now ~0.2s.- PyPI metadata. 21 keywords added, richer classifiers, Issues + Changelog URLs, description names Obsidian compatibility explicitly.
- README restructure. New "Ideal for" tagline, "When to use / When not to use" sections, compact "How it compares" table (vs Obsidian core, Obsidian semantic plugins, ripgrep, build-your-own RAG), "Support & limitations" matrix, and a CI tests badge.
llms.txtat the repo root per llmstxt.org.- CI honest.
|| truedropped fromVerify install; Python matrix now covers 3.11, 3.12, 3.13, 3.14. - Repo-wide improvements. New
CHANGELOG.md(Keep a Changelog format), 19 GitHub topics for discoverability.
Install
pip install --upgrade seeklink
# or
uv tool install seeklinkRecommended usage
export SEEKLINK_VAULT=/path/to/vault
seeklink search "machine learning"First call after a cold boot: ~2s (spawns the daemon, loads the embedder). Every call after that: ~10ms without reranker, ~0.5s with reranker.
Full changelog
See CHANGELOG.md.
Diff from v0.2.0: v0.2.0...v0.2.2
v0.2.1 — NOT PUBLISHED on PyPI (superseded by v0.2.2)
Warning
This tag was published on GitHub but never made it to PyPI. A duplicate license declaration broke the build. Everything described below shipped in v0.2.2. Do not pin to seeklink==0.2.1 — it does not exist on PyPI. Use pip install seeklink==0.2.2 or later.
(Original v0.2.1 notes preserved below for history.)
TL;DR — The daemon now actually auto-spawns (README promised, code finally delivers). Searching and indexing via seeklink on a warm daemon are back to ~10ms per call. Stale daemons can no longer silently serve the wrong vault or wrong-model results. Plus a cleaner CHANGELOG, richer PyPI metadata, restructured README, and an llms.txt for AI-agent discoverability.
No breaking changes. Pure additive + bug fixes.
See v0.2.2 release notes for the full content.
v0.2.0 — CLI-first with MLX reranker
What's new
SeekLink v0.2 is a major architecture refresh: the MCP server is replaced by a CLI + Unix-socket daemon, and an optional cross-encoder reranker brings precision gains on Apple Silicon.
CLI-first architecture
- MCP server removed. All interaction is now via
seeklink search / index / status / daemon. - Daemon mode (
seeklink daemon): keeps the embedding model resident in memory. First query ~2s (model warmup), subsequent queries ~10ms. Auto-spawns on first use, never auto-exits. - Leaner dependencies:
mcp[cli]andwatchfilesremoved. 4 runtime deps instead of 6.
MLX reranker (Apple Silicon)
- Qwen3-Reranker-0.6B via MLX runs on Metal GPU for cross-encoder precision boosting.
- Scores each (query, passage) pair with full cross-attention — more accurate than vector similarity alone.
- ~60ms per pair on M3 Air. Default enabled; disable with
SEEKLINK_RERANKER_MODEL="". - 100+ languages including Chinese and English. Apache 2.0 license.
Improved search fairness
- Title weight 3.0 → 1.5: log entries and journal notes now compete fairly with titled permanent notes in search results. Override per query with
--title-weight.
Freshness checks replace file watcher
- Bidirectional mtime scan on every
search/status: detects new files, modified files, and deleted files. - Warns to stderr instead of silently going stale. No background daemon required.
- Full vault re-index (
seeklink index) now prunes deleted entries from the database.
Security
- Path traversal protection on
seeklink index(rejects../escapes). - Concurrent daemon startup detection prevents orphaned processes.
Breaking changes
seeklink serveis removed. Useseeklink daemonfor resident mode, or invoke CLI commands directly.- Default
title_weightchanged from 3.0 to 1.5. Pass--title-weight 3.0to restore old behavior. mcp[cli]dependency removed. Agents should call seeklink viasubprocessorcli_clientinstead of MCP tools.
Configuration
| Variable | Default | Description |
|---|---|---|
SEEKLINK_VAULT |
. |
Vault root path |
SEEKLINK_EMBEDDER_MODEL |
jinaai/jina-embeddings-v2-base-zh |
Embedding model |
SEEKLINK_RERANKER_MODEL |
mlx-community/Qwen3-Reranker-0.6B-mxfp8 |
Reranker (empty = disabled) |
Stats
- 182 tests passing
- 2 rounds of adversarial code review (Codex), 6 findings, all resolved
- Benchmarked on real bilingual vault (Chinese + English, 50 notes / 505 chunks)
v0.1.0
Initial open-source release.
Features:
- Four-channel hybrid search (BM25 + vector + indegree + title/alias) with RRF fusion
- Knowledge graph from
[[wikilinks]]with BFS traversal - Link discovery:
suggest_linksfinds missing connections,resolve_suggestionwrites them - Tag and folder filtering
- Alias support in search and link resolution
- Native CJK: jieba tokenization + jina-v2-zh bilingual embeddings
- CLI mode:
seeklink search,seeklink index,seeklink status - File watcher with automatic indexing and deleted file cleanup
- 6 MCP tools, fully local, headless (no Obsidian required)
- 217 tests, Python 3.11+
Install:
pip install seeklink
See README for setup instructions.