Give your saved bookmarks a lifecycle: 24 hours to decide, 30 days to watch, or keep. Nothing is ever deleted — lapsed items just leave your attention, not your disk. A local MCP server, no accounts, no cloud.
Strong tool definitions with excellent descriptions (avg 250+ chars) and clear parameter documentation. All 7 tools have explicit schemas with proper types and enums. Naming is verb-forward and unambiguous (intake, decide, undo, restore). Output structures are well-documented in descriptions. Main gaps: no explicit error handling guidance in tool descriptions, no per-tool permission/scope declarations, and output schemas are described narratively rather than as formal JSON Schema objects returned to the client.
Apply a judgment to one or more items: keep (move to `kept`), watch (move to `watching` for a 30-day hold), or drop (move to `lapsed`). Each item's history records the decision, the timestamp, and the actor claim (user/ai/mcp-client). `actorClaim: "ai"` is rejected unless the user has set BOOKMARKS_LIFECYCLE_AUTO_DECIDE=true — but real protection against unwanted changes comes from every mutation being undoable via `undo`, not from this field. Batch up to 25 items per call.
Scan browser bookmarks (via bookmarks-mcp) and merge them into the lifecycle: new URLs land in `inbox` with their real save date persisted; already-tracked ones get reconciled (sources, title). Never deletes a record — a URL missing from every source that was successfully scanned gets `sourceGone: true`, not removed. A source that failed to read (e.g. Safari without Full Disk Access) is never treated as confirming a URL is gone. Check `sourceStatus` in the response before assuming an empty result means nothing was found. This call may first persist lazy expiry/drip housekeeping (see README) even if you only meant to read.
List all items in a given layer (inbox, pending, watching, kept, lapsed), oldest first. Each item includes `remainingMs` until it lapses on its own (null for kept/lapsed). This is a read-only snapshot; use `decide` to move items between layers. This call may first persist lazy expiry/drip housekeeping (see README) even if you only meant to read.
Restore one or more items from `lapsed` back to `pending` (the daily queue). Useful if you accidentally let something expire or changed your mind. Each restore is recorded in history as a user decision. Batch up to 25 items per call.
Output schemas are documented in prose descriptions but not exposed as formal JSON Schema objects in tool definitions. Clients cannot programmatically understand response structure.
No error handling guidance in tool descriptions. Tools mention they 'may throw' (undo) but do not explain recovery steps or error categories (retryable vs user-fixable vs fatal).
No tool annotations (readOnlyHint, destructiveHint, idempotentHint) declared in schema. Clients cannot infer which tools are safe to retry or which mutate state without parsing descriptions.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 63 | 2026-07-28+ | v2 |
Aggregate counts: how many items in each layer, how many have ever been decided, how many are marked sourceGone. Useful for dashboards and progress tracking. This call may first persist lazy expiry/drip housekeeping (see README) even if you only meant to read.
The 24-hour layer, oldest first — the actual to-do list. Each item includes `remainingMs` until it lapses on its own. `hasEverIntaken: false` means nothing has ever been scanned in (an empty pending list in that case means "you haven't started", not "you're caught up") — call `intake` first. This is where daily_triage starts. This call may first persist lazy expiry/drip housekeeping (see README) even if you only meant to read.
Undo the last state change (a decision, an expiry, or a drip). Returns the item to its previous state and removes the last history entry. Can be called repeatedly to walk back multiple changes. Throws if there is nothing to undo (the item has no history beyond its creation).
Parameter descriptions lack explicit format/constraint guidance. E.g., 'source' param says 'Filter by browser' but does not enumerate valid browser names or explain how to discover them.
No scope/permission declarations. Tools like 'decide' and 'restore' mutate state but do not declare required permissions (e.g., 'write:bookmarks', 'write:lifecycle').