# Changelog
All notable changes to textlog are documented here.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [0.1.9] - 2026-05-06
### Changed
- **MCP server `instructions` rewritten as recipe + veto.** Old text
only described the response shape, so Claude Code often shelled out
to `tl --help` + `tl logs` to "discover" features it already had
via MCP — wasting ~500 tokens per session before the first useful
call. New instructions explicitly list call recipes (`latest →
textlog__get_recent(n=1)`, `today → textlog__list_today`, etc.) and
veto the CLI path for reads. Adds ~120 tokens once at handshake,
recovers ~5× on every clipboard lookup. No schema or behavior
changes — restart Claude Code to pick up the new handshake string.
## [0.1.8] - 2026-05-05
### Added
- **Body pagination on `textlog__get_capture`.** A 49 KB capture
overflowed the MCP per-tool token budget when fetched in one shot.
`get_capture` now accepts optional `offset` (default 0) and `limit`
(default 8000 chars, capped at 32000) and returns `text_offset`,
`text_total_chars`, and `truncated` so callers can page through any
size body. Bodies smaller than the default window return in one
shot exactly as before.
## [0.1.7] - 2026-05-04
### Changed
- **Breaking MCP shape.** `CaptureSummary.text` is now `text_preview` —
the first 200 characters of the capture body — accompanied by a new
`truncated: bool` flag. List-style responses (`textlog__get_recent`,
`textlog__list_today`, `textlog__search`) no longer dump full
clipboard bodies into Claude's context. A 5-row `get_recent` that
used to spend ~10 k tokens on large copies now returns ~250 tokens.
- The `id` field on every summary doubles as a handle for the new
full-body fetch.
### Added
- `textlog__get_capture(id)` — returns the full untruncated body for a
single capture. Use this when `text_preview` was marked
`truncated: true`. Errors with `INVALID_PARAMS` if the row was
trimmed by the ring buffer or the id never existed.
- `Storage::get_by_id(id)` on the SQLite layer powering the new tool.
- Server-instructions string updated so Claude is told to expand
truncated previews via `get_capture` instead of guessing at body
length.
### Why
Before this release the MCP server eagerly serialized the entire
clipboard body for every recent capture, so a single large copy could
blow past 10 k tokens on a default `n=5` request. The fix is at the
response shape, not the on-disk layout — splitting the daily Markdown
file into per-capture chunks would have moved bytes around without
changing what MCP returns. Truncating at the wire boundary plus a
lazy-fetch tool gives the same coverage at ~10× lower token cost.
## [0.1.6] - 2026-04-19
### Changed
- **Breaking default.** `notifications.copy_log_path_on_complete` now
defaults to `false`. Previously the daemon wrote the daily-MD path
back to the clipboard after every capture, which cascaded in
clipboard managers and surprised users who only expected textlog to
*read* the clipboard. Claude already discovers the daily-MD via
`md_path` in MCP responses since v0.1.1, so the write-back hasn't
been necessary for a while.
- Existing configs are not rewritten. If you have
`copy_log_path_on_complete = true` in `~/textlog/config.toml` and
want the new behavior, set it to `false` (or delete the line).
## [0.1.5] - 2026-04-19
### Performance
- Move the `NSPasteboard.changeCount` check out of `spawn_blocking` —
it's a microsecond i64 property read, not a blocking call. The
blocking-pool handoff was paying a task alloc + context switch every
tick for nothing.
- Only enter `spawn_blocking` when the counter actually advances and
string / PNG content needs to be read.
- Exponential idle backoff: active rate = `poll_interval_ms`, doubles
to a 2 s ceiling after 20 unchanged ticks; any real change snaps
back to active.
- Default `poll_interval_ms` raised from 250 to 500 ms (matches
Maccy). Idle wakeups drop by roughly an order of magnitude.
### Added
- `tl perf` command: samples the running daemon's CPU% and RSS via
`ps` and reports min/avg/max, with config-driven context (poll
interval, backoff ceiling) and a verdict line. Flags:
`--duration <secs>` (default 10), `--interval-ms <ms>` (default
1000).
### Docs
- README notes the launchd respawn-throttle workaround after a binary
upgrade (`tl uninstall && tl install` clears the throttle).
## [0.1.4] - 2026-04-17
### Fixed
- MCP stdio deadlock: no longer hold `std::io::stdout().lock()`
across `run_mcp` dispatch. The rmcp stdio transport writes from a
`spawn_blocking` worker thread that needs the same reentrant lock,
which caused `initialize` to hang silently. Each subcommand now
locks stdout on its own.
## [0.1.3] - 2026-04-17
### Added
- Lowercase `-v` short flag alongside `-V` / `--version` / `tl
version` — all four paths resolve to the same handler.
- `tl update` command: self-updater that shells out to `cargo install
textlog --force` and prints the `tl uninstall && tl install` hint
to re-bootstrap the LaunchAgent.
## [0.1.2] - 2026-04-17
### Added
- Storage benchmark (`bench_storage_at_scale`): inserts 10k rows,
measures FTS5 search latency and daily MD archive size to set a
performance baseline.
### Docs
- README expanded with real scenarios, full MCP tool reference,
tuning recipes, and tilde-path policy.
## [0.1.1] - 2026-04-17
### Added
- `md_path` field on every `CaptureSummary` so Claude can cite the
daily MD archive directly. Makes the daily-archive paste trick work
without `notifications.copy_log_path_on_complete` — recommended for
users whose clipboard manager (Raycast, Maccy, Paste, Alfred)
cascades on the path-back-to-clipboard write.
## [0.1.0] - 2026-04-17
### Added
- Initial public release on crates.io.
- NSPasteboard polling pipeline with privacy filter and per-capture
SHA-256 dedup.
- Apple Vision OCR (`VNRecognizeTextRequest`) for clipboard images
and ad-hoc files, with `accurate` / `fast` recognition levels and
configurable language + confidence thresholds.
- SQLite FTS5 ring buffer (bounded query index) plus a permanent
daily Markdown archive under `~/textlog/logs`.
- MCP stdio server exposing six tools: `textlog__get_recent`,
`textlog__list_today`, `textlog__search`, `textlog__ocr_latest`,
`textlog__ocr_image`, `textlog__clear_since`.
- `tl doctor` with eight health checks: config file, log dir, SQLite
+ FTS5, pasteboard access, notifications, LaunchAgent, MCP
registration, Vision smoke test.
- LaunchAgent lifecycle: `tl install` / `uninstall` / `start` /
`stop` / `status`.
[Unreleased]: https://github.com/xicv/textlog/compare/v0.1.5...HEAD
[0.1.5]: https://github.com/xicv/textlog/releases/tag/v0.1.5
[0.1.4]: https://github.com/xicv/textlog/releases/tag/v0.1.4
[0.1.3]: https://github.com/xicv/textlog/releases/tag/v0.1.3
[0.1.2]: https://github.com/xicv/textlog/releases/tag/v0.1.2
[0.1.1]: https://github.com/xicv/textlog/releases/tag/v0.1.1
[0.1.0]: https://github.com/xicv/textlog/releases/tag/v0.1.0