Skip to content

Releases: simonsysun/seeklink

SeekLink v0.7.0

07 May 03:56

Choose a tag to compare

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]" or uv tool install "seeklink[mcp]".
  • Run seeklink mcp --vault PATH to expose search, get, status, and doctor to 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

05 May 20:11

Choose a tag to compare

SeekLink v0.6.1

SeekLink v0.6.1 is a small daemon lifecycle and documentation release.

Highlights

  • Added public daemon controls:
    • seeklink daemon status
    • seeklink daemon stop
    • seeklink daemon restart
    • seeklink daemon pid
  • Added SEEKLINK_DAEMON_IDLE_TIMEOUT.
    • Default: 900 seconds / 15 minutes.
    • Set 0, off, false, or no to 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.txt so users and agents can understand
    why a local Python process 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-daemon
    • SEEKLINK_NO_DAEMON=1 seeklink search "query"
    • seeklink search "query" --vault PATH
  • Existing seeklink daemon --vault PATH behavior remains available; the clearer
    spelling is now seeklink daemon run --vault PATH.

Verification

  • uv run pytest -q
  • git diff --check
  • CLI smoke for daemon status, daemon restart, daemon pid, daemon stop,
    doctor --json, status --json, search --json, and get -C
  • uv build
  • uvx 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

05 May 03:29

Choose a tag to compare

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 doctor and seeklink doctor --json for lightweight environment and index diagnostics.
  • New --no-daemon and SEEKLINK_NO_DAEMON=1 for deterministic cold-start behavior in scripts and agents.
  • Improved optional MLX Qwen3 reranker path: --rerank-k auto now 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.txt guidance, 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 build and twine check passed.
  • 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 sqlite3 module to be linked against SQLite 3.45+ with FTS5.
  • No cloud service or API key is required.

SeekLink v0.5.0

04 May 17:27

Choose a tag to compare

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 index reports progress on stderr and keeps the final Done: summary on stdout, including the SEEKLINK_VAULT daily-use path.
  • Better PKM defaults: todo/ and archive/ 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 --json and status --json remain the structured CLI surface.
  • get PATH:LINE -C N remains a direct filesystem read for precise context windows.
  • Full-vault index progress stays on stderr so stdout stays parseable.
  • llms.txt now documents optional reranker installation, first-run/model-download caveats, and the SQLite runtime requirement.

Upgrade Notes

  • Run seeklink index once for each vault after upgrading so v0.5 can write index metadata and rebuild derived index contents if needed.
  • SeekLink requires Python's sqlite3 module 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

29 Apr 04:11

Choose a tag to compare

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 --json and seeklink status --json for agent-friendly structured output.
  • seeklink get PATH:LINE -C N for 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 search now defaults to --rerank-k auto.
  • Existing indexes migrate to schema v3 and mark sources unprocessed so the next seeklink index populates heading metadata.

Fixed

  • Avoids sqlitefts crashes 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 N now really limits cross-encoder candidates even when N < --top-k.
  • search and index auto-restart a stale daemon when vault/model config changes.

v0.3.2

24 Apr 06:52

Choose a tag to compare

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

  • search results are anchored to specific line ranges. CLI prints SCORE 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

19 Apr 16:51

Choose a tag to compare

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.2seeklink==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 index without --vault auto-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 status probe, so switching SEEKLINK_VAULT or SEEKLINK_EMBEDDER_MODEL no longer silently returns results from the wrong DB. On non-Apple-Silicon where mlx_lm can't load, the daemon's self-disabled reranker is accepted so the daemon-first workflow still works there.
  • seeklink status stays 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.txt at the repo root per llmstxt.org.
  • CI honest. || true dropped from Verify 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 seeklink

Recommended 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)

19 Apr 06:52

Choose a tag to compare

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

16 Apr 06:54

Choose a tag to compare

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] and watchfiles removed. 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 serve is removed. Use seeklink daemon for resident mode, or invoke CLI commands directly.
  • Default title_weight changed from 3.0 to 1.5. Pass --title-weight 3.0 to restore old behavior.
  • mcp[cli] dependency removed. Agents should call seeklink via subprocess or cli_client instead 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

04 Apr 23:36

Choose a tag to compare

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_links finds missing connections, resolve_suggestion writes 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.