Release 2.0 — LinkBar - #49
Merged
Merged
Conversation
Squashed reintroduction on a clean base (earlier branch history had swept-in build artifacts). SwiftUI MenuBarExtra over `lnk --json`: - Live kqueue watchers on the workspace — the badge and popover update the moment a session hook writes a capture; verified live. - One field, two verbs: Enter asks memory, ⌘↩ remembers (review-gated). - Capture rows show "Will save: <first proposal>" via capture-inbox previews; timestamps disambiguate same-titled sessions. - Recall always answers: results, honest abstention, or "no matches". - Secret refusals from the new remember gate surface as a friendly flash; stale-runtime warnings show a banner with one-click Fix. - Launch at login (SMAppService), settings sheet, reveal-in-Finder on every row, auto-fading toned flashes, ⌘R/⌘Q, version footer. - LINKBAR_SNAPSHOT=/path.png renders the popover to PNG through an offscreen AppKit window for screenshot verification.
Direction: a native macOS inbox with Link's editorial soul — system materials and SF Pro do the structure, rust does the opinion, one serif wordmark is the signature. - DesignSystem.swift: LinkBrand tokens (rust with a lifted dark-mode variant, 4/8 spacing rhythm), SectionHeader (tracked uppercase labels with count badges — rust when work is pending), HoverRow, and the serif Wordmark. - Rust replaces default-blue everywhere an action lives: Accept, review checkmark, the remember ⊕, settings toggle, Fix button. - Real hierarchy: titles at 12.5 medium, metadata in tertiary, memory type in rust, timestamps inline; search field with an embedded magnifier; two-tone "Will save:" previews. - Designed idle state (rust seal, "All reviewed.") instead of empty sections; flash is a toned pill that slides in and fades. - LINKBAR_APPEARANCE=light|dark forces the snapshot appearance so both modes are verified from the command line.
…Extra windows (Done dismissed the popover, state stuck)
Research into how the hook grabs session context surfaced three misalignments, now fixed: - Standing rules survived: extract_transcript_text gains keep_head, and the hook mines a head+tail window (9k) instead of recency-only 6k. A rule stated at the start of a long session no longer falls off the front. Verified live on an 82-turn session. - Correct attribution at accept time: the capture records a ## Proposal Source block (the user's own turns); accept-capture and the inbox preview mine from it, so the assistant's prose beneath the notes is never re-proposed as the user's preference. Closes a regression the earlier hook-time fix didn't cover. - The pipeline is reviewable: session-end persists a decision trail (## How Link Read This Session), surfaced on the dashboard Captures page (proposals + collapsible trail) and in capture-inbox --json with a mined_from_user_turns flag.
# Conflicts: # CHANGELOG.md # tests/test_capture_core.py
Inch-by-inch review of every surface plus RepoBar-inspired features.
Bugs fixed:
- start() ran on every popover open, stacking a 5-min timer and
rebuilding watchers each time; now guarded to run once per launch.
- Watchers for raw/memory-captures failed silently on a fresh
workspace (directory not yet created) and stayed blind until
restart; they now self-heal after the first capture creates the dir.
- LogEntry.id was timestamp+operation, which collides when one command
writes twice in a second and made ForEach drop rows; id now includes
the description.
- memory-log emits oldest-first; "Recent activity" and the "Latest:"
line wanted newest-first — now reversed.
- Dashboard viewer probe trusted any responder on :3000; it now
requires the Link viewer page (200 + "Link" in body) so a foreign
dev server on that port isn't mistaken for ours.
- Bundle CFBundleShortVersionString was 0.1.0 while the UI said 0.5;
both are now 0.6.0 from one LinkBrand.version constant.
Features:
- Idle state replaced with a living overview: active/total memories,
wiki pages, and to-review counts as stat chips, plus a 14-day
activity sparkline and the latest operation with relative time.
- Multi-proposal captures get an Accept menu (pick which proposal);
single-proposal stays a one-click Accept.
- Recall rows gain Copy text; the search field gains a clear button.
- Capture timestamps show local relative time ("2h ago") instead of
raw UTC.
- Menu-bar icon shows "!" when the workspace runtime is stale (repair
is one click) even when nothing is pending.
Verified via light/dark snapshots against both released lnk (graceful
fallback: no proposals/trail) and dev lnk (full 1.7 rendering: "Will
save" preview, decision-trail disclosure, provenance). Installed and
running as 0.6.0.
Cold-user walkthrough found the automatic loop's worst first impression:
a one-click Accept (LinkBar) and accept-capture --index 1 landed on
whichever proposal came first in the transcript, which is often a
throat-clearing preamble ("I want to set some conventions…") rather
than the rule ("From now on I only deploy on Fridays…"). Both classify
as preferences at score 90, so confidence alone can't separate them.
- memory_durability_rank scores concrete directives (an action verb, or
only/always/never/by default) above statements that are merely about
making rules (want/need to set/establish + conventions/guidelines/…).
propose_memories_from_text stable-sorts by it, so index 1 is the
substance. Bare temporal phrases ("from now on", "going forward")
don't count as concrete — they attach to preambles just as easily.
Ordering only; every proposal still appears for review.
- README Quick Start collapses three parallel entry points (proof / try
+ serve / onboard x5) into one two-command hero path.
- lnk onboard collapses a fresh workspace's dozen scaffold lines into a
one-line summary; targeted repairs on an existing workspace still list.
LinkBar showed your memory but was silent about Link's own health — so a stale MCP runtime, unwired hooks, or a missing semantic tier would quietly degrade recall with no signal. New Status tab makes the whole plumbing visible and self-healing. - Tabbed shell: Inbox · Status · Settings (slim rust segmented bar; Inbox carries the pending badge, Status shows an amber dot when a surface needs attention). Settings moves from a sheet-like pane to a proper tab. - Status dashboard: a health row per surface — CLI, Workspace, MCP, Hooks (Claude Code), Recall power (semantic tier + rerank), Viewer — each a colored dot + one-line state, fed by status/verify-mcp/ semantic --json plus a direct read of the agent's hook config. Heavy probes (verify-mcp, semantic) are gated to once/15s and run after the fast data paints, so the popover stays instant. - One-click remediation on every unhealthy row: Refresh (stale runtime), Fix (MCP version drift), Wire (Claude Code hooks), Enable (semantic recall), Open (viewer). - Menu-bar icon shows a subtle amber dot when any surface is unhealthy even with an empty review inbox — Link tells you before recall quietly gets worse. Verified via light/dark snapshots against a real workspace: it correctly flags this machine's stale MCP (1.5.0 ≠ 1.6.0) with a Fix button and lexical-only recall with an Enable button.
Clicking "Enable" on the Recall row flashed "Semantic recall ready." and then the row stayed "Lexical only" — because the fix flashed success on exit 0 without checking whether anything changed. On a released (pre-1.7) CLI, `semantic --setup` only prints the manual pip steps and exits 0, so nothing was installed. Every remediation now confirms the real outcome and flashes the truth: - Enable (semantic): runs --setup, re-reads `semantic --json`, and reports "ready — <tier>" only if it actually enabled, else the exact manual command to run. - Fix (MCP): runs the precise upgrade command verify-mcp emits (venv pip install --upgrade link-mcp==<version>) via a new LinkCLI.runRaw, re-checks verify-mcp, and reports success only if it's ready — not a workspace init that never touched the venv. - Wire (hooks): re-reads the settings file to confirm the hook landed. No more optimistic flashes; the dot and the message always agree.
The three How-it-works demos stacked as full-width centered figures ran ~1800px of scroll, with captions as afterthought lines. Each demo is now a flex row — terminal beside its caption as real side prose with a rust kicker (REMEMBERS / RECALLS BY MEANING / STAYS TRUE) — zigzagging left/right. ~40% less scroll, editorial rhythm, and the side text keeps a row alive during the animations' brief between-scene gaps. Narrow viewports wrap back to the stacked layout (flex-wrap, no media queries needed inside the template). Goes live with the next develop→main merge.
The first ambient feature: LinkBar's memory is no longer trapped behind the menu-bar icon. Press ⌥⌘M anywhere and a floating panel opens over whatever you're in. - Type to recall — results stream as you type (debounced), Enter copies the top hit to the clipboard, Esc closes. Confidence chips and the honest "don't know" abstention carry over from core recall. - Prefix "+" to remember — "+ staging moved to port 4000" saves a review-gated proposal without leaving your editor. Secret-refusal and duplicate/conflict feedback shown inline. - Carbon RegisterEventHotKey needs no permissions (unlike global event monitors that require Input Monitoring), so it works in the unsigned/ ad-hoc build. Non-activating NSPanel floats over full-screen apps and all Spaces. Same lnk --json backend — no new surface. This turns LinkBar from a menu-bar inbox into a system capability: Spotlight, but for your agent memory.
Second ambient feature. LinkBar now detects live agent sessions (a Claude Code project whose newest transcript was written in the last 5 minutes) and shows the pulse: - A breathing green dot + "N agents active · project names" row atop the inbox, with the last memory activity's relative time. - The menu-bar icon gains a quiet green dot when agents are working and nothing needs review — memory being made, no action required. Priority order in the label: pending count > active pulse > amber health warning. - Zero polling loops: computed during the existing refresh pass from transcript mtimes (they stream continuously while a session runs — verified live). Codex/Cursor roots can join the same scan later. Verified via snapshot against the real workspace: the pulse correctly detected the very session that wrote this commit.
Third v2.0 feature: when a session capture lands, post a native banner with the "Will save:" proposal preview and an Accept action, so the review gate meets you the instant memory is proposed. Full UNUserNotificationCenter wiring: capture category, Accept/Review actions, accept-by-path from the banner, present-while-frontmost. FINDING (the reason this ships dormant): tested notification authorization on the installed ad-hoc-signed bundle, launched properly via LaunchServices, on macOS 26.5.2 — result: granted=false status=denied "Notifications are not allowed for this application" macOS ties notification permission to a stable code signature; an unsigned/ad-hoc app is denied outright and can't even prompt. So the feature is gated on the real authorization result: on the current free unsigned build it stays completely inert (no dead API calls, no console spam), and it lights up automatically the day LinkBar ships signed + notarized — which is now the single concrete thing the $99 Apple Developer enrollment buys. Everything else in v2.0 (palette, pulse, browser) works free.
Fourth v2.0 feature. New Memory tab between Inbox and Status: - Reads wiki/memories/*.md directly (the local-first move: the browser shows your actual files, no intermediary), parsing only the frontmatter the rows display; refreshed with the normal refresh pass and the existing directory watchers. - Search-as-you-filter, type chips (preference/decision/note/project/ procedure/fact), and an archived toggle; superseded and needs-review states surface inline, supersede lineage on hover. - Row actions: copy the claim, reveal in Finder (double-click too), archive/restore via the CLI. Snapshot-verified against the real workspace (6 active memories render with correct types, scopes, projects, and dates).
Three liveliness upgrades (pattern-inspired, not copied):
- Version banner above the header: "New · Link 1.7.0 is out — secret
gate, capture provenance, ranked proposals →" linking to the GitHub
release. One line that says the project is alive.
- The agent picker now pays its rent: each agent tab swaps in the real
one-command setup (lnk onboard --agent <x> --hooks --write for
hook-capable agents, --write otherwise) instead of the legacy
bash integrations/<x>/install.sh scripts that predate 1.7's
self-provisioning onboard.
- New § ORIGIN section between Benchmarks and Setup: "It started with
a Karpathy gist." — the LLM-wiki post, what Link grew from it, and
the honest kinship line ("Other branches of the pattern graph your
code. Link remembers you."), linking the original gist.
Verified rendering locally (banner, origin, and live per-agent command
swap all present; legacy install.sh commands gone; JSON template valid).
…is total not active (was the 16-of-6 nonsense)
…0 checklist; homepage LinkBar section
The banner advertises a download and links the release tag, so a stale version points visitors at a tag that does not exist yet. It now moves with the other 5 version files instead of relying on someone remembering it at release time.
Made the release script hard-fail on minimal trees (its own tests build a fake repo without docs/). The homepage is presentation, not a package artifact — update it when present, skip it otherwise.
…p the obsolete manual-venv MCP steps
The 1.7 hardening and 2.0 work removed two type errors; locking the lower number in means they can't quietly come back.
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.
Link 2.0.0 — the memory layer gets a face
LinkBar puts the review gate in your macOS menu bar. The memory layer is unchanged in shape (plain Markdown, review-gated writes, no LLM in the write path) — it's just no longer only a CLI and an MCP server.
No breaking changes. Every CLI command, MCP tool, hook, and memory file from 1.7 works as before. The major version marks LinkBar's debut, not an API break.
LinkBar 1.0 (macOS,
apps/LinkBar— Swift/SwiftUI overlnk --json)+to rememberbrew install --cask gowtham0992/link/linkbarAlso
lnk semanticreported "Indexed 16 of 6" — the denominator counted active-only while the index embeds every memoryprepare_release.pynow bumps the homepage release banner with the version filesVerification