Prepare 1.6.0 release - #46
Merged
Merged
Conversation
…pture at end lnk connect claude-code --hooks installs SessionStart/SessionEnd hooks that run the new agent-agnostic 'lnk hook' runtime: session-start injects a bounded project-scoped memory brief, session-end extracts bounded transcript text (skipping tool calls/outputs) into the review-gated session-end capture path. Settings writes are idempotent and preserve existing user hooks; the hook runtime never fails the agent session. Claude Code is the first wired agent; the hook agent table is ready for others.
…ion loop - lnk connect --hooks now supports Codex (~/.codex/hooks.json, nested schema, session-start only: Codex has no session-end event) and Cursor (~/.cursor/hooks.json, flat version-1 schema, JSON additional_context envelope via lnk hook --emit cursor), alongside Claude Code. - Session-end capture noise controls: sessions with no memory-worthy proposal candidates are skipped and duplicate end events are deduplicated with a local fingerprint, so automatic hooks cannot flood the inbox. - New lnk consolidate and MCP review(action=consolidate): a read-only backlog plan with pending captures, review queue, duplicate-capture groups, and paste-safe accept/discard commands. The injected session-start brief nudges the agent to offer consolidation when the backlog crosses thresholds; nothing is ever merged, deleted, or saved without per-action user approval.
Lexical recall stays the default and the fallback. With the optional link-mcp[semantic] extra and a one-time explicit 'lnk semantic --setup', a small local static-embedding model (model2vec potion-base-8M) retrieves close paraphrases that token matching misses, across CLI recall, memory briefs, MCP recall, and smart query packets. Local-first guarantees preserved: the model loads offline-only so recall can never trigger a download; embeddings are plain JSON in .link-cache/; similarity is in-process cosine with no vector database or service; LINK_SEMANTIC=off disables the layer. Scoring is standout-based (z-score against the corpus for each query) because raw cosine thresholds are not comparable across queries with static models. Semantic-only matches are labeled match=semantic with capped confidence so agents verify paraphrases before acting on them, and they never outrank exact lexical hits. New scripts/eval_recall_quality.py benchmarks lexical vs hybrid with a regression gate. Real-model results: paraphrase hit@1 0.50 -> 0.62, hit@3 0.62 -> 0.75; exact-token queries unchanged at 1.00.
- scripts/recall_dataset.py: deterministic, fully authored benchmark corpus (62 memories incl. 20 distractors, 294 authored queries + phrasing variants = 1,176 cases). Queries are classified by MEASURED significant stemmed-token overlap with their target, so the zero-overlap paraphrase group is provable, not asserted. - scripts/eval_recall_quality.py: hit@1/3/5, MRR@5, per-domain breakdown, recall latency, JSON output, small (CI) and full suites, and a hard regression gate: hybrid may never score below lexical on any metric. CI runs the gate with a deterministic abstaining fake embedder. - benchmarks/RESULTS.md: methodology, hardware, model-size ablation (potion-base-8M vs 32M), honest limitations, and reproduction steps. Measured (Apple M4, real model): token-overlap hit@1 0.589 -> 0.703, zero-overlap paraphrase hit@3 0.064 -> 0.136 and hit@5 0.082 -> 0.202, ~2.8 ms per recall in-process. - python -m link_mcp --semantic-setup: explicit one-time model fetch and index build for MCP-only installs (found during an external-customer walkthrough: pip-only users had no lnk CLI to enable semantic recall). The serving path still never touches the network.
…, architecture-first positioning 1. Paraphrase recall: measured that static embeddings are the ceiling (retrieval-tuned potion-retrieval-32M and multi-view embeddings did not move zero-overlap results; ablations documented). Added a second local provider tier — fastembed all-MiniLM-L6-v2 (contextual ONNX) — preferred automatically when installed, with the static model kept as the instant-load fast tier for CLI and hooks. Quality tier on the full 1,176-case suite: token-overlap hit@1 0.589 -> 0.749; zero-overlap paraphrase hit@3/hit@5 ~4x lexical (0.255/0.338); ~10 ms per recall. Offline guard verified empirically for both providers: a recall can never download a model. 2. Self-authored benchmark: added a third-party track. scripts/eval_locomo.py scores the retrieval stage of LoCoMo (ACL 2024) with turns as memories and evidence-annotated questions as queries — no LLM anywhere. Hybrid lifts any-evidence hit@10 0.578 -> 0.685 and evidence recall@10 0.517 -> 0.608 across 1,536 third-party queries over 5,882 turns. Dataset downloaded by the user (CC BY-NC 4.0, Snap Inc.), never redistributed; the script contains no network code. 3. Positioning: rewrote docs/why-link.html to lead with the four architectural commitments (readable Markdown memory, review-gated writes, no LLM in the memory layer, CI-enforced zero network), with named Mem0/OpenMemory and Zep/Graphiti comparisons and the benchmark as supporting evidence. README and RESULTS.md updated with tiered and third-party numbers.
…v guidance, loop consistency - Documented hooks, semantic recall, and consolidation in every surface an external user or agent reads: PyPI package README, LINK.md, installed agent instructions (both variants), the MCP link://instructions resource, the docs landing page copy, and the CLI reference. - connect/onboard --hooks now refresh a workspace runtime that predates session hooks (preview warns, --write repairs), preventing exit-2 hook noise after upgrades. - lnk semantic now names the interpreter it checked and, when the Link MCP Python differs, prints the exact venv-side setup command (python -m link_mcp --semantic-setup), fixing the extras-in-the-wrong-env trap. Quality-tier setup states the ~5s CLI load tradeoff explicitly. - The memory-backlog consolidation nudge moved into the core brief payload, so CLI start, MCP briefs, skills, and hooks all surface it consistently (and the hook no longer double-scans captures). - lnk onboard gained --hooks; hook captures are titled with their project; consolidation groups near-duplicate captures by token overlap, not just exact matches; semantic status counts active memories only; Codex/Cursor hook support is labeled as new in output and docs.
Walked the product as a brand-new user (fresh clone, fake HOME, README paths: proof -> onboard --hooks --write -> day-1/day-2 hook briefs -> semantic status -> consolidate -> common mistakes) and fixed what hurt: - Empty-workspace session-start briefs are now two actionable lines (seed project context, approval rule) instead of a fifteen-line skeleton of zeros injected into every new session on day one. - Every 'Missing wiki directory' CLI error (25 sites) now prints a concrete next step: point at your workspace or lnk init here. - Verified end-to-end in the walkthrough: onboard --hooks --write writes MCP config plus both hooks in one command; the stale-runtime guard warns in preview and repairs on write; day-2 briefs recall real memories; consolidate and semantic empty states read cleanly.
- getting-started.html: new steps 9 (session hooks: one command makes the memory loop automatic) and 10 (optional hybrid semantic recall with both tiers and MCP-only setup), onboard --hooks example, ToC entries. - mcp.html: semantic extras + --semantic-setup in the MCP-only install, offline-loading guarantee, hooks-installed workflow note, and the review consolidate action. - security.html: privacy bullets for offline-only semantic models, plain JSON embeddings, and proposal-only hook capture. - Landing page: design-principle cards updated — hooks-injected shared memory, and 'No services, no APIs' reworded for the optional local semantic tier measured in the open. - README now reads as a product doc: new 'Why Link Is Different' section (four architectural commitments + measured-not-asserted with benchmark links) placed before Quick Start; recall/review tool bullets cover match labels and consolidate; privacy section covers semantic offline loading and proposal-only hooks.
…ansion Both candidate mechanisms measured worse than or equal to the shipped approach on the recall benchmark; documented so the methodology shows its negative results.
A full editorial audit before the 1.6.0 cut found the flagship features documented on the primary surfaces (README, landing, getting-started, CLI, MCP, why, security) but absent from the surfaces skill-first agents and troubleshooting users actually read: - Official skills: link-memory teaches the hooks-installed rule (skip the manual brief) and the read-only consolidation pass; link-retrieve teaches confidence + match labels (verify semantic/weak matches); link-health adds the lnk semantic status check. - memory-contract.html: the hooked loop, honest recall signals, and the consolidate action are now part of the documented contract. - concepts.html: hybrid two-tier retrieval and the automatic lifecycle (automation changes when memory is proposed, never who decides). - skills.html: the two new agent rules. - troubleshooting.html: 'Session Hooks Are Not Firing' (including hook session-end --explain) and 'Semantic Recall Is Not Working' (wrong-interpreter, setup, kill-switch causes). - scale.html: links the measured recall benchmarks.
'no embeddings' became imprecise once optional local embedding tiers shipped; the footer now says 'no services', matching the design principle card. Also ignore local .claude/ tooling configs.
…asured The flagship features existed on the home page only as card fine print; the hero and meta description still told the pre-1.6 story. A skimming visitor never learned the two headline facts. The hero paragraph and meta description now lead with them: memory injected automatically at session start, proposals at session end with every save approved by the user, and hybrid local recall measured in the open.
The 1.6 hero rewrite kept four of the five founding claims (inspectable wiki, review-gated saves, local, cross-agent) but dropped the provenance word. Source-backed memory is a load-bearing differentiator, not decoration; it belongs in the first paragraph a visitor reads.
Every release pulls attention toward its newest features; three releases from now the site could read like a benchmark product with the founding story reduced to a footnote. This test encodes the claims that made Link through 1.5.0 — source-backed provenance, inspectable Markdown, review-gated writes, local-first, cross-agent, the proof loop — and fails any landing or README rewrite that drops one, so forgetting becomes a deliberate decision instead of an accident.
Markdown wraps lines mid-phrase; the guard now judges claims on prose, not line breaks.
The guard protects claims, not exact strings: the cross-agent pillar now accepts the README's established phrasings (shared across multiple agents, reusable by different agents) alongside the landing's literal wording.
Went through the exact path a brand-new user walks (README -> proof -> onboard -> try the pitch) and hit real walls where the two headline 1.6 features were hidden or silently off. Fixes: P0 - flagship features were undiscoverable on the guided path: - lnk onboard now surfaces the automatic-memory path: explains --hooks and prints the ready-to-run --agent <hook-capable> --hooks --write command; each hook-capable agent preview offers 'Make memory automatic (recommended)'. Before, onboard never mentioned hooks at all. - A recall that finds nothing while memories exist now tells the user paraphrase matching (semantic recall) is off by default and how to enable it, instead of a bare 'No matching memories found'. The README paraphrase example is reframed as opt-in and the landing hero calls hybrid recall optional, so the marquee demo never reads as a broken default. P1 - command identity whiplash and workspace confusion: - Source-checkout commands now show a friendly 'python3 link.py' instead of the raw interpreter path (python@3.14 ...); Homebrew users still see plain lnk. - lnk proof labels its workspace a throwaway demo, adds a 'what this means for you' line, and points to lnk onboard for real memory. P2: - prepare_release.py reminds maintainers to bump the Homebrew tap so brew install never serves an older Link than the docs describe. Four regression tests pin the onboard-hooks and recall-miss-hint behaviors. 819 tests + guards green.
Second cold new-user walk: after 'onboard --agent X --hooks --write' succeeded, the generic 'add --hooks' teaching hint still printed at the bottom, telling the user to do the thing they just did. Suppress the generic hint when the user already passed --hooks; the teaching still fires for users who onboard without it.
…or README GIF) The cold new-user walk showed the two mind-blown moments were told in prose but never shown. Now they are: - docs/assets/link-aha.svg: a hand-built, brand-matched animated terminal (plain text, no external runtime, no binary, theme-safe dark terminal) looping the two aha moments — recall that matches 'how should I name my git branches' to a 'feat/short-topic' memory (meaning, not keywords), then a new agent session greeted with memory automatically. Embedded at the top of the Getting Started page; registered in the media verifier. - docs/media/link-aha.tape: a charmbracelet vhs script that renders the matching README GIF from real lnk commands, with the one-time render command in its header. The GIF is not checked in until rendered, so no binary or broken reference lands early. Option 2 (the site SVG) ships now; option 1 (the README GIF) renders with one 'brew install vhs' when ready.
Rendered docs/assets/link-aha.gif (144K) with charmbracelet vhs from the checked-in tape: real 'lnk recall' output showing a memory saved as 'Name branches feat/short-topic, never long' surfacing for the query 'how should I name my git branches' — different words, match: moderate, matched by meaning. Placed near the top of the README with a caption, registered in the media verifier. Hardened the tape's cleanup (capture the original dir before cd) and gitignored docs/media/.aha-demo so a render can never leave a stray workspace to be committed.
The landing described the product and had a decorative hero graph but showed no real product output. Embedded the animated demo terminal (the existing self-contained link-aha.svg) in the 'How it works' section, right after 'the agent builds the memory' and before the Capture/Compile/Remember steps — a 'here's the payoff, then here's how' beat. Verified with a headless-Chrome render of the live bundle: the first insertion broke it (the landing template is JSON, and I'd escaped single quotes as \' which JSON rejects). Reverted and re-inserted with JSON-valid escaping; the page now renders end to end.
Session-end hooks extracted the whole transcript (user + assistant) and fed it to the memory-proposal extractor, which is speaker-blind. A cue like the assistant writing "you prefer small commits" was mined and proposed as the user's own preference — found while dogfooding 1.6. Mine proposals from the user's turns only via a new roles= parameter on extract_transcript_text; keep the full transcript in the raw capture for review context via session_end(proposal_text=...). Precision over recall for automatic writes: the user can always remember explicitly, and junk proposals are worse than the occasional miss. Regression tests cover both the extractor (assistant prose excluded, user preference kept) and the hook (assistant-only session captures nothing; a user-stated decision still captures).
Cold-walking 1.6.0 as a brand-new pip user: python -m link_mcp --help was swallowed by parse_known_args (add_help=False) and the stdio server started, hanging in the terminal with zero output — a dead end on the first exploratory command anyone runs. Handle -h/--help explicitly before the parser: print the module usage docstring (install, usage, MCP config snippet) plus an options list and exit 0. Agent launch behavior is unchanged; unknown args still never crash the server. Regression test asserts --help exits 0 with usage on stdout and nothing on stderr.
First Windows CI run of the hooks tests (CI is PR-triggered, so the 1.6 work had only seen POSIX until the release PR) failed on two assertions, both test bugs — the product output is correct on both platforms: - test_build_preview_includes_both_events_and_commands asserted POSIX shlex single-quoting; display_command intentionally uses list2cmdline double quotes on Windows. Assert the platform's quoting. - test_connect_hooks_preview_includes_session_hooks_payload compared the absolute temp path, but Windows mkdtemp returns the 8.3 short form (RUNNER~1) while the built command holds the resolved long form (runneradmin). Assert the stable demo/link.py path tail instead.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Prepare 1.6.0 release