Add durable bookmarks across CLI and TUI - #121
Open
tony wants to merge 18 commits into
Open
Conversation
tony
force-pushed
the
issue-80-deterministic-identities
branch
from
July 12, 2026 20:14
adcf5e0 to
cb6377d
Compare
tony
force-pushed
the
issue-80-deterministic-identities
branch
9 times, most recently
from
July 14, 2026 03:56
a68c683 to
5ffd718
Compare
tony
force-pushed
the
issue-80-deterministic-identities
branch
from
July 14, 2026 23:36
5ffd718 to
4e49bbd
Compare
tony
force-pushed
the
issue-80-deterministic-identities
branch
from
July 18, 2026 11:40
4e49bbd to
c755ba0
Compare
tony
force-pushed
the
issue-80-deterministic-identities
branch
from
July 19, 2026 01:06
c755ba0 to
a0c10d6
Compare
tony
force-pushed
the
issue-80-deterministic-identities
branch
from
July 19, 2026 01:42
a0c10d6 to
68db741
Compare
This was referenced Jul 25, 2026
tony
force-pushed
the
issue-80-deterministic-identities
branch
from
August 1, 2026 18:28
e32fa8c to
d9e1601
Compare
tony
force-pushed
the
issue-79-bookmarks
branch
from
August 1, 2026 18:43
59e775f to
4fcdccb
Compare
tony
force-pushed
the
issue-80-deterministic-identities
branch
from
August 9, 2026 12:04
d9e1601 to
629ed55
Compare
tony
force-pushed
the
issue-79-bookmarks
branch
from
August 9, 2026 12:15
4fcdccb to
9dbaacc
Compare
tony
force-pushed
the
issue-80-deterministic-identities
branch
from
August 9, 2026 12:29
629ed55 to
c9e4ed6
Compare
why: Canonical records need a bounded, privacy-minimal bookmark layer that survives CLI and later TUI sessions without mutating agent-owned stores. what: - Add strict versioned bookmark values and transactional XDG persistence. - Add idempotent add/remove/list CLI actions with deterministic output. - Cover validation, durability, permissions, atomicity, and safe errors.
why: Existing snapshots could retain permissive modes, direct callers could receive path-bearing filesystem errors, and custom stores changed caller-owned parent permissions. what: - Repair snapshot modes through the descriptor held under the stable lock. - Translate storage failures into generic path-free, unchained errors. - Preserve existing explicit parent modes while securing owned directories. - Cover each review finding with focused regression tests.
why: Canonical bookmarks need a keyboard-first HUD surface. Saved targets must resolve without freezing Textual or replacing active search state. what: - Add bookmark slash commands, focus-safe toggling, and a compact recall modal. - Offload bookmark loading, identity work, transactions, and target resolution. - Gate writes and callbacks while preserving results and marking saved records. - Cover modal behavior, races, privacy, pump bounds, and guards.
why: Recall could snapshot entries before an accepted write became durable, while a concurrent toggle left an older resolver able to open a stale modal. what: - Reject recall while a bookmark transaction is pending. - Cancel and invalidate active resolution before launching a write. - Cover both mutation and resolution race interleavings.
why: First-hit resolver coverage and tiny modal fixtures could miss regressions at the fixed 200-entry boundary. what: - Mount and navigate a full-capacity filtered recall modal. - Exercise target-last and target-absent resolver scans under the watchdog. - Assert every candidate hashes off-pump without a heartbeat stall.
why: A find query opened while large-body preparation was pending searched a bounded prefix but retained those incomplete matches after the final body arrived. what: - Recompute live find state when worker-prepared detail becomes visible. - Cover a match beyond the pending prefix and retain existing pending behavior.
why: Durable bookmarks span CLI and HUD behavior and need one privacy-conscious contract for canonical targets, local state, and current-store recall. what: - Add the canonical scope, storage, and CLI guide with ADR 0016. - Document HUD toggles, filtering, resolution, and unresolved retention. - Add the release deliverable, indexes, and documentation contract tests.
why: Record additions require a content validator while removals do not. A re-add also depends on matching the saved validator, even at capacity. what: - Scope --content-id to record add and document remove syntax. - Explain matching re-adds and mismatched-validator exit behavior. - Pin the distinction in the bookmark documentation contract.
why: Long canonical IDs made the record-add example exceed the command width used by the documentation. what: - Put the content-ID flag and record target on continuation lines. - Keep the console block as one copyable shell command.
why: Bookmark titles and bodies may contain Textual markup-like text. Parsing that content could alter the preview or abort modal mounting. what: - Disable markup parsing for the bookmark preview widget. - Mount a malformed-markup title and assert it renders literally.
why: Following a sidecar-lock symlink could change and lock an unrelated file. Non-regular descriptors are also invalid lock transaction anchors. what: - Open the lock without following symlinks and verify its descriptor type. - Refuse unsafe locks before chmod or flock with path-free public errors. - Preserve a symlink target byte-for-byte and cover non-regular descriptors.
why: The bookmark TUI depended on the package facade in violation of the module boundary, while the public Task 1 dispatcher was not re-exported like its sibling command dispatchers. what: - Import bookmarks from its owning module in the HUD. - Re-export the bookmark dispatcher through the package facade. - Pin only BookmarkArgs and run_bookmark_command in the facade snapshot.
why: Inserting the bookmark parser among required ParserBundle fields broke callers that construct the longstanding four-parser bundle positionally or by keyword. what: - Append the bookmark parser as an optional compatibility field. - Keep internally-created bundles wired to the bookmark-specific parser. - Cover the original positional and keyword constructor forms.
why: A mutation may finish after the live detail record has been rebuilt as a distinct Python object with the same canonical identity. Object comparison left that equivalent record unstarred. what: - Match mutation refreshes against the cached canonical record ID. - Keep unrelated live selections untouched without hashing on the pump. - Mount equivalent and unrelated records around a mutation regression.
why: Wall-clock heartbeat gaps conflate a blocked Textual pump with host CPU descheduling, making off-pump bookmark tests flaky on shared runners. what: - Hold resolver and detail workers on GIL-releasing events. - Prove pump progress through a scheduled callback and live key handling. - Keep watchdog runtime and dedicated watchdog tests unchanged.
why: The rebased bookmark test no longer matches the repository Ruff formatting. what: - Reflow the resolver fixture comprehension without changing behavior.
why: The original fixture included its query in the raw body, so it could not prove that async rendering recomputes live detail-find matches. what: - Use minified JSON whose pretty form introduces the queried spacing. - Assert the match appears only after the render worker completes.
why: Ruff's format gate rejected the focused bookmark tests after the stack was replayed onto the updated identity branch. what: - Apply Ruff's canonical wrapping to CLI and command tests.
tony
force-pushed
the
issue-79-bookmarks
branch
from
August 9, 2026 12:30
9dbaacc to
f18d51e
Compare
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.
Summary
Add durable, private bookmarks keyed by canonical content, stored-occurrence, or thread handles without copying prompt bodies or modifying source histories.
agentgrep bookmark add|remove|listwith idempotent human and JSON workflows, a versioned 200-entry snapshot, private XDG storage, atomic replacement, and symlink-safe locking.bbinding,/bookmark [record|content|thread], and a compact/bookmarksrecall list with resolved and unresolved entries.Relationship
This PR targets the branch for #111 because deterministic record identities are its prerequisite. It is independent of the export PR and can be retargeted to
masterafter #111 lands.Closes #79
Tested
ty, 2,769 passed, 3 skipped, 3 expected failures, and Sphinx.Goal
Idempotent completion condition for
/goal. It asserts an end state, not an action: if the state already holds, the first evaluation passes and nothing is edited.git rev-parse --abbrev-ref HEAD && git -c rerere.enabled=false merge-tree --write-tree --name-only issue-80-deterministic-identities HEAD && grep -A3 '^## Status' docs/dev/adr/*durable-bookmarks.md && NO_COLOR=1 AGENTGREP_TUI_WATCHDOG=1 PATH=$PWD/.venv/bin:$PATH env -u VIRTUAL_ENV -u UV_NO_SYNC ./.venv/bin/python -m pytest -m '' --reruns 0 -q