Skip to content

Releases: ygtalp/rawthink-mcp

v2.0.1: release plumbing

Choose a tag to compare

@ygtalp ygtalp released this 31 Jul 06:01

No functional change. Two release-plumbing defects, both found by publishing 2.0.0 for real rather than by reading the specification.

The MCP registry ownership marker was missing. The registry proves that a publisher controls a PyPI package by finding mcp-name: <server-name> in the package README. 2.0.0 shipped without it, and PyPI versions cannot be re-uploaded — so the fix costs a version. The publish workflow now checks for the marker before it waits on the release, not after.

The publish workflow assumed a tag ref. workflow_dispatch runs on a branch, so GITHUB_REF_NAME was main and every manual run died comparing a branch name against a version number. Tag and manual paths are handled separately now, and both verify that server.json, its package entry and pyproject.toml agree.

Both were verified against the published schema and a parsed workflow file before 2.0.0 went out. Neither check exercised the path that failed.

If you are on 2.0.0 there is nothing to do — the package behaves identically.

v2.0.0: stable BM25 term IDs, atomic writes, doctor

Choose a tag to compare

@ygtalp ygtalp released this 31 Jul 06:00

Requires a full reindex. After upgrading, run reindex(full=True) from a session. A plain reindex skips unchanged chunks and leaves the old sparse encoding in place — which is how a corrupt index survived the documented remedy.

Coming from 0.x, migrate the graph first with python -m rawthink_mcp.migrate --guess-domains --heal-dangling --apply. rawthink-doctor tells you what is still pending.

Why this release exists

BM25 term IDs were positions in a sorted vocabulary. One new token sorting early shifted every ID after it, so sparse vectors written before a reindex stopped matching queries encoded after it.

Nothing failed. RRF kept returning good results off the dense side, so search felt fine while half the retrieval system scored noise.

Measured on a real vault of 1,841 chunks:

before after
sparse MRR 0.1596 0.6259
sparse nDCG@10 0.1851 0.6320
sparse hit@10 5/19 14/19
dense MRR 0.6842 0.6842

Dense staying identical is what makes the sparse delta attributable to the fix.

A second finding

The measurement that confirmed the bug also surfaced something the audit had not predicted: 40 of 69 sessions in that vault had never been indexed. The files were on disk, search could never find them, and nothing said so. After indexing the sessions the evaluation needed, dense MRR went 0.6842 → 0.9474 and sparse 0.6259 → 0.8395.

The stale index was costing more than the encoding bug. Both were invisible, and together they read as one vague sense that search could be better. rawthink-doctor now checks for exactly this.

New

  • rawthink-doctor — nine checks with a fix line for each failure: vault, graph schema, BM25 state format, Qdrant, index coverage, vector dimension, Ollama, MCP registration.
  • Concurrent writes are safe. Graph mutations take a file lock and a thread lock. Measured before the fix, with three processes writing: one writer's twelve updates all vanished, silently.
  • Graceful shutdown releases the Qdrant directory lock and the graph file lock on SIGINT/SIGTERM. POSIX only — Windows terminates rather than signalling.
  • 104 tests, no Docker and no Ollama required, running on 3.10–3.13 in CI.
  • index_vault(force=True), so a full reindex actually re-encodes.

Changed

Term IDs are a hash of the token; format_version is 2 and legacy state is rejected rather than loaded. BM25 state lives with the vault instead of the package directory. Diagnostics go to stderr — they were going to stdout, which is the JSON-RPC channel, so the record of what an indexing run skipped never arrived anywhere. Graph search matches prefixes, not substrings. open_nodes is a pure read. get_session_chunks pages.

Reading

docs/postmortem-bm25-term-drift.md — how a defect stayed invisible for months, and what made it visible.

Full detail in CHANGELOG.md.

v1.5.0: controlled vocabulary, single write path

Choose a tag to compare

@ygtalp ygtalp released this 31 Jul 05:59

Schema and packaging release. The graph gets a controlled vocabulary and a single validated write path; the sdist stops shipping the test suite.

Known issue in this version. Sparse retrieval is degraded by a term-ID defect that produces no error and is hidden by RRF fusion — measured on a real vault at MRR 0.16 where it should be 0.63. You will not notice it from search results. Fixed in 2.0.0; see the postmortem. If you are installing fresh, install 2.0.1 instead.

Why this release exists

A real vault reached 46 entity types and 66 relation types across 173 entities. Two causes.

entityType was answering two questions at once — what role does this node play, and what subject is it about — so the list grew by one entry per topic. Splitting subject into its own domain field collapses the type list to ten and keeps it there.

Non-canonical relation types were accepted with a warning. Nothing acted on the warning, so 56 one-off types accumulated unnoticed. The graph stayed writable and stopped being queryable.

Breaking

Existing vaults must be migrated before this version can write to them.

python -m rawthink_mcp.migrate --guess-domains --heal-dangling          # dry run
python -m rawthink_mcp.migrate --guess-domains --heal-dangling --apply

A timestamped backup is taken before anything is written.

Highlights

  • record(), record_decision() and revise() — one validated, all-or-nothing write path. record_decision stores what was rejected, which is the part that exists nowhere else once the code is written.
  • entityType closed to ten roles; domain, visibility and observation kind added.
  • Unknown relation types are rejected rather than warned about.
  • search_nodes is bounded and reports total_matched, so a truncated result is visible.
  • Tool profiles: recall (4 tools, ~900 tokens), record (5, ~1750), full (17, ~4200).
  • serverInfo.version reports the package version instead of FastMCP's.
  • The published 0.1.4 sdist contained tests/, whose fixtures hardcoded personal entity names and session dates. pyproject.toml now has an explicit allowlist and the evaluation set loads from RAWTHINK_EVAL_GT.

Full detail in CHANGELOG.md.

v0.1.4

Choose a tag to compare

@ygtalp ygtalp released this 20 Apr 08:27

What's Changed

  • Consistent project directory: rawthink-install now creates a self-contained project directory with vault, CLAUDE.md, THINKING_DIRECTIVES.md, SETUP.md, docker-compose.yml, and /rtclose command — same structure as git clone
  • Fix config.py MEMORY_FILE: default path now derives from RAWTHINK_VAULT instead of package location (broken for pip install users)
  • Fix rtclose export path: persist/session_export.pyrawthink-export entry point
  • Upgrade-safe hooks: re-running rawthink-install updates vault path in settings.json instead of skipping

v0.1.2

Choose a tag to compare

@ygtalp ygtalp released this 14 Apr 15:18

Initial public release.

  • 15-tool MCP server for Claude Code persistent memory
  • Hybrid search: BGE-M3 dense + BM25 sparse with RRF fusion
  • JSONL knowledge graph with belief revision and activation decay
  • Session lifecycle: /rtclose export, entity extraction, handoff
  • rawthink-install CLI for one-command setup
  • Multi-terminal safe handoffs