Productivity

bear-note-organizer - Claude MCP Skill

Triages untagged Bear notes (macOS) using the user's established tag taxonomy. Use when the user asks to process, organize, triage, clean up, or tag their Bear notes. Pattern-matches capture types (letters, media discoveries, addresses, URLs, image-only) to existing destinations, surfaces ambiguous items for explicit decision, executes approved writes via Bear's URL scheme, verifies in the DB, and updates itself with new rules at the end of each session.

SEO Guide: Enhance your AI agent with the bear-note-organizer tool. This Model Context Protocol (MCP) server allows Claude Desktop and other LLMs to triages untagged bear notes (macos) using the user's established tag taxonomy. use when the user ask... Download and configure this skill to unlock new capabilities for your AI workflow.

🌟1 stars β€’ 0 forks
πŸ“₯0 downloads

Documentation

SKILL.md
# bear-note-organizer

Triage the user's untagged Bear notes inbox to zero. **Triage-only**; not a general note-management skill. Periodic hygiene (stale `active`, duplicate detection, orphan-tag sweep) is intentionally deferred.

## When to invoke

- User explicitly asks: "triage my Bear notes", "process untagged notes", "organize my Bear inbox", "/bear-note-organizer"
- Do NOT auto-trigger on every Bear-related question

## Pre-flight (mandatory, in order)

1. Verify Bear is running: `pgrep -x Bear`. If not running, **abort and ask the user** β€” never fall back to direct DB writes without explicit opt-in.
2. Read the **Session Learnings** appendix at the bottom of this file.
3. (Optional) Read `references/tag-conventions.md` for format details.

## Workflow

### Step 1 β€” Query the inbox

DB path:
```
~/Library/Group Containers/9K33E3U3T4.net.shinyfrog.bear/Application Data/database.sqlite
```

Untagged-active query (read-only, safe with Bear running):
```sql
SELECT n.Z_PK, n.ZUNIQUEIDENTIFIER, n.ZTITLE,
       SUBSTR(COALESCE(n.ZTEXT,''), 1, 250) AS preview,
       datetime(n.ZMODIFICATIONDATE + 978307200, 'unixepoch', 'localtime') AS modified
FROM ZSFNOTE n
LEFT JOIN Z_5TAGS jt ON jt.Z_5NOTES = n.Z_PK
WHERE n.ZARCHIVED = 0 AND n.ZTRASHED = 0 AND n.ZPERMANENTLYDELETED = 0
  AND jt.Z_13TAGS IS NULL
ORDER BY n.ZMODIFICATIONDATE DESC;
```

Schema essentials are in `references/schema-cheatsheet.md`.

### Step 2 β€” Categorize

Group untagged notes into bins:
- **Auto-batch candidates**: matches R9 (letter/card) or R10 (empty placeholder)
- **Investigation needed**: matches R11 (image-only), R12 (bare URL), or has ambiguous title
- **Recommend-only**: novel patterns or items needing user judgment

### Step 3 β€” Investigate

For investigation-needed notes:

- **Image-only notes (R11)**: locate via `find` under `~/Library/Group Containers/9K33E3U3T4.net.shinyfrog.bear/Application Data/Local Files/Note Images/` (each image lives in its own outer-UUID subdirectory). `Read` the image; reference what's visible in the recommendation.
- **Bare URL notes (R12)**: `WebFetch` the URL β€” usually returns title; that's enough. `WebSearch` for disambiguation if title is ambiguous.
- **Multiple parallel investigations**: spawn an **agent team** via `TeamCreate` so investigators share findings rather than working blind. See `references/agent-teams-pattern.md`.

### Step 4 β€” Present and approve

- **Auto-batch candidates**: present grouped, ask for one batch confirmation, then execute.
- **Investigations**: present results + recommendations with rationale, wait for explicit approval.
- **Any `replace_all` on a user-created note** (folding into a list note, retitling): show **exact** new body as a preview before firing (R3, non-negotiable per user feedback memory).

### Step 5 β€” Execute

Use `scripts/bear_writes.py` helper (or the patterns documented there). All writes go through `bear://x-callback-url/*` β€” never direct SQLite writes.

The helper auto-snapshots prior body to `/tmp/bear-rollback/{uuid}-{timestamp}.md` before any `replace_all` (R5).

### Step 6 β€” Verify

Sleep ~3 seconds (Bear processes URL events asynchronously), then re-query the DB. Present a **terse** verification table:

| Op | Target | Expected | Observed |
|----|--------|----------|----------|
| TAG | 94 | +personal/correspondence/2026 | βœ… |
| ARCH | 111 | archived=1 | βœ… |

If all OK, report "all N operations verified." Flag discrepancies only.

### Step 7 β€” Update self

At end of session, append any new rules / refined heuristics / notable decisions to the **Session Learnings** appendix at the bottom of this file, with a date stamp. Protocol in `references/self-update-protocol.md`.

Also: if a new tag branch was created or a new pinned-list destination emerged, update the `Tag Taxonomy` note in Bear (see "Tag Taxonomy reference note" below).

## Triage rules

### Tag conventions (matching user's existing style)

- **R6.** Trailing `#` on every tag: `#personal/correspondence/2026#`
- **R7.** Write parent + child explicitly: `#personal/correspondence# #personal/correspondence/2026#` (Bear auto-creates the parent from the leaf, but matching existing notes keeps the user's text consistent)
- **R8.** Multiple tags on one line, space-separated
- **R21.** Tags describe **domains** (`personal/`, `tech/`, `finance/`), not **states** β€” except `active`, the one orthogonal state tag. Never propose `tech/active/` or similar; combine `category` + `active` instead.
- **R22.** Maximum nesting depth: **3 levels**. If a 4th feels needed, that's a signal to flatten or split horizontally.

### Pattern matching

- **R9.** Title matches `^(Letter|Card) (to|from) ` β†’ propose `personal/correspondence/{current-year}` (auto-batch after one batch confirmation)
- **R10.** Empty placeholder (no title AND body matches `^[#\s]*$`) β†’ propose trash without lengthy preview
- **R11.** Single-image note (body is `![](...png)` only) β†’ read the image first; reference what's visible in the recommendation
- **R12.** Bare URL note (title === body === a single URL) β†’ fetch metadata, propose new title + 1-line description + `active` tag
- **R13.** Identifiable single media (movie / TV / book) β†’ fold into the appropriate pinned list note and **archive the source in the same operation pair**
- **R14.** Address capture (text screenshot containing a mailing address) β†’ tag `personal/correspondence/{year}` + `active` (user transcribes to Apple/Google Contacts later; no consolidation note)
- **R18.** Articles **about** people the user knows β†’ `personal` (or appropriate sub-branch); **not** `personal/correspondence/*` which is reserved for letters

### Person tags (R23, R24)

When a note is about a specific family member or friend by name, add a person leaf tag:
- Family: `#personal/family/{first-last-kebab}#` (e.g., `#personal/family/ian-paglia#`)
- Friends: `#personal/friends/{first-last-kebab}#`

Bear auto-creates the relationship parent (`personal/family` / `personal/friends`).

The 3rd-instance rule (R16β€²) does **not** apply to adding new person leaves within an existing relationship branch β€” adding a 1-of-1 person tag is always fine. The rule is about inventing new *category* branches, not new *people*.

### Stewardship

- **R15.** Don't silently create new tag branches. Always propose with rationale.
- **R16β€².** Promote an ad-hoc category to a formal sub-branch only on the **3rd** instance (Johnny.Decimal heuristic). Force-fit into the existing parent for the first two.
- **R17.** Don't touch titles unless the user asks. The "Scanned Documents.pdf" suffix in correspondence titles is intentional Bear behavior β€” leave it alone.

## Safety rules (non-negotiable)

- **R1.** Bear must be running before any writes.
- **R2.** Read-only DB queries are unrestricted (SQLite WAL allows concurrent readers).
- **R3.** Preview every `replace_all` on a user-created note before firing.
- **R4.** Verify every write batch by re-querying the DB.
- **R5.** Save prior body to `/tmp/bear-rollback/{uuid}-{timestamp}.md` before any `replace_all` (helper does this automatically).

## Pinned list notes (fold-and-archive destinations)

| List | Z_PK | UUID | Purpose |
|------|------|------|---------|
| Media Queue | 37 | 22E69F7E-8AD4-44F5-8D27-9263F7F9D12C | TV / Movies / Books to consume |
| Movies for mom | 32 | 2019AB24-D732-441E-8301-CDB6C149C560 | Movies curated specifically for mom |
| Wish List | (re-query) | β€” | Things wanted |
| Gift Ideas | (re-query) | β€” | Gifts to give |
| Tech Watch List | 93 | (re-query) | Tech to evaluate |
| Skills to Install | 31 | (re-query) | Claude Code skills to set up |
| People to Visit | 92 | (re-query) | People to see in person |
| Trip Expenses | 30 | (re-query) | Per-trip costs |

Z_PKs may shift over time; UUIDs are stable. Re-query when in doubt:
```sql
SELECT Z_PK, ZUNIQUEIDENTIFIER, ZTITLE FROM ZSFNOTE WHERE ZPINNED=1 AND ZTRASHED=0;
```

When folding a source note into a list, **always** archive the source in the same operation pair. Never leave loose source notes alongside the canonical list.

## Tag Taxonomy reference note

The user has a pinned `Tag Taxonomy` note in Bear (tagged `#lists#`) that documents the live taxonomy. Update it whenever:
- A new tag branch is created
- A new pinned-list destination emerges
- A new convention is agreed

Use `replace_all` with preview, like any other user-created list note.

## Investigation toolbelt

- Read images: `Read` tool on the absolute file path
- Fetch URL metadata: `WebFetch` (often returns just title; usually enough)
- Web research: `WebSearch` for "what is X?" disambiguation
- Multiple parallel investigations: `TeamCreate` agent team (see `references/agent-teams-pattern.md`) β€” never isolated `Agent` calls when 2+ investigations could share context

## Deferred for future versions

- Periodic hygiene: stale `active` items (>30 days), duplicate detection, orphan-tag sweep (<3 notes)
- Auto-update on schedule (currently strictly on-demand)
- Title cleanup proposals beyond image-only / bare-URL cases

---

## Session Learnings (auto-maintained)

Date-stamped entries appended after each triage session. Add new rules / refined heuristics / notable decisions; do NOT rewrite earlier entries. Append-only β€” preserve history.

Format:
```
### YYYY-MM-DD β€” short-session-tag
- Rule / refinement / decision (with brief rationale)
- (Optional) reference to specific note PKs that prompted it
```

### 2026-04-26 β€” initial-bootstrap
- Skill bootstrapped from a 19-note triage session that drove untagged-active count from 18 β†’ 0
- Confirmed user's existing tag conventions: trailing `#`, parent+child explicit, max 3 levels, `active` is the sole state tag
- Created new branch `personal/family` (1 note: Ian Paglia article)
- Established person-leaf convention `personal/family/{name-kebab}`; first leaf `ian-paglia` linked to 2 notes
- Folded Familiar Touch (2024) into "Movies for mom" list β€” note this is a separate destination from main Media Queue, specifically for mom-curated picks
- User confirmed: address captures stay per-note (no master Address Book consolidation); user transcribes to Apple/Google Contacts manually
- Agent teams (TeamCreate) authorized for parallel investigation phase

### 2026-05-01 β€” cunard-cruise-merges
- 27 β†’ 0 untagged-active in one session (largest run to date)
- **New rule R25: Multi-screenshot recipe/article merges.** When 2+ image-only notes are sequential parts of the same source (e.g., scrolling screenshots of one recipe), user prefers a single merged note over individual tagging. Detect via: same source citation visible in multiple images (e.g., "Arnaud's Restaurant +6" badge), shared topic, sequential content. Always preview the merged body (R3) β€” keeper is the chronologically-first note (lowest content order, not lowest PK). Archive the rest. Cross-note image refs by UUID DO resolve in Bear regardless of source folder; verified working.
- **New rule R26: Cruise-context grouping.** Notes captured during an active trip cluster strongly β€” itinerary docs, restaurant research, food/drink recipes, dish allergens, search results all belong with the trip tag. When `travel/{trip-slug}-{year}` already exists and a note's content matches the trip's window (date, location, ship/operator named), tag it without prompting. The "Queen's Grill" / Cunard / port-city signals were strong enough to auto-batch this session's 8 cruise notes.
- **Created branch `personal/health`** β€” first instance: cruise dish allergen requiring trigger-identification follow-up (PK 140). User explicitly authorized; tagged with `active` for follow-up.
- **Gift Ideas restructured** with per-recipient `## {Name}` sections (## Mom, ## The Paglias). Sterling silver subsection under Mom. Adding `#active#` to the list note itself flags pending shopping/follow-up. Recommended over creating a duplicate "gifts for friends and family" pinned list β€” existing Gift Ideas already serves that purpose per Tag Taxonomy.
- **YouTube comment screenshots are usually trash unless they reference a specific film/title the user wants to remember.** Multiplicity (1996) reference (PK 127) was real β†’ fold into Media Queue. Balls Up (2026) meme thread (PK 123) was humor β†’ trash. When ambiguous, ask β€” don't guess.
- **Member Statement PDF (PK 141)** force-fit to bare `finance` tag per R16β€² (1st instance). Promote to `finance/statements` on 3rd instance.
- Final taxonomy snapshot saved in PK 113 (Tag Taxonomy note).

### 2026-05-01 β€” active-tag-discussion-triage
- **First "active triage" variant session.** User asked to discuss/process notes tagged `active` (vs. the standard untagged-inbox triage). Same fold-and-archive primitives applied cleanly; no new tooling required. The discussion-first approach (group by likely close action, then drill in) worked well β€” user confirmed Group B fold + PK 142 tag in one batch.
- **New rule R27: Active-triage close actions.** For each `active` note, the close action is one of: (a) **fold into a list + archive source** (R13 β€” applies to identifiable media, queued videos, etc.), (b) **complete the action and drop `active`** (e.g., make recipe, schedule visit), (c) **add missing domain tags** if the note has only `active` and no domain (PK 142 had only `active`; fixed by mirroring PK 140's tags), (d) **defer** if still genuinely pending. List notes themselves keep `#active#` until the list is processed.
- **New rule R28: Mirror-tag from a sibling note.** When a note is the deep-dive / research writeup of an event already documented in another tagged note (e.g., PK 142 = Fructan research for the same dish that PK 140 captured), mirror the sibling's domain tags rather than re-deriving. Saves judgment cycles and keeps related notes findable together.
- **Stub notes that turn out to be media titles** still resolve via R13. PK 114 was a 29-char stub ("My one and only", no URL, 12-second create-to-modify window). User confirmed it referenced *My One and Only (2009)* film β†’ folded into Media Queue + archived. Pattern: when an aborted-capture stub's text matches a real media title, ask the user; don't trash on length alone.
- Result: 14 β†’ 10 active notes. Remaining 10 are list notes (5) and genuine pending follow-ups (5).
- **New rule R29: OmniFocus handoff for genuine to-dos.** When an `active` Bear note is really a deferred to-do (not reference material, not a decision-pending list), the close action is: create an OmniFocus inbox task with the actionable verb in the title (e.g., "Plan next cruise", "Make a hummingbird") and put the bear:// URL in the task notes, then archive the source. Bear stays a knowledge store; OmniFocus owns the action queue. Pattern: `bear://x-callback-url/open-note?id={UUID}` is a stable round-trip link.
- **OmniFocus Ruby manager (`omnifocus_manager.rb --create`) failed with `-1700` "Can't convert types"** even when `--project` was omitted (Inbox target). AppleScript fallback worked: `tell application "OmniFocus" / tell default document / make new inbox task with properties {name:"...", note:"..."}`. Document this in the omnifocus skill if it persists.
- **New rule R30: Cross-note links for paired knowledge.** When two notes document the same incident from different angles (e.g., the dish PK 140 + the diagnostic research PK 142), link both directions using `bear://x-callback-url/open-note?id={UUID}` rather than wikilink `[[Title]]`. UUIDs survive renames; titles don't. Preserve first-line title per R17 by placing annotations BELOW any embedded PDF/image.

### 2026-05-13 β€” nyc-trip-cluster
- 15 β†’ 0 untagged-active in one session. Created new trip branch `travel/nyc-2026` (3 notes: itinerary feedback PDF, Mayfair Hotel booking, Lost Boys ticket). Followed established `travel/{trip-slug}-{year}` pattern from cunard-2027 and panama-canal-2026 β€” confirmed by user up-front rather than waiting for 3rd-instance rule (per-trip leaves are exempt from R16β€²).
- **New rule R31: Verify fold destination contents before proposing.** Before recommending "fold X into Media Queue", read the relevant section of the destination first. Saved a duplicate-entry bug this session: 3 of 4 proposed media folds (Sheep Detectives PK 204, Sandman + WWDITS PK 200) were already in the Television section β€” correct action was archive-only, not fold-then-archive. Without the destination check, I would have created stale duplicates the user would have to manually de-dupe. Applies to all pinned list notes.
- **New rule R32: Use Bear's `header` param on `add-text` to splice into sections without `replace_all`.** For pinned list notes (Media Queue, Gift Ideas, etc.) where a new item belongs under a specific `## Heading`, call `_fire('add-text', id=UUID, mode='append', header='Television', text='* New title')` directly rather than reading-then-replacing the whole body. Avoids: (a) R3 preview overhead, (b) context bloat from multi-KB list bodies, (c) any chance of corrupting unrelated sections. Helper doesn't expose `header` yet β€” call `_fire` directly. Preserves the auto-snapshot guarantee since `replace_all` is the only mode that needs it.
- **R12 refinement: YouTube comment-thread screenshots default to trash unless a *named title* surfaces.** Three YT comment shots this session (PKs 197, 198, 199): one humor short was trashed wholesale; one (PK 196) was rescued because a comment explicitly named "Movie name: Irish Wish" β†’ fold into Media Queue.Movies + archive. Heuristic: if the only "content" is comment-thread humor with no named work to remember, trash. If a comment names a real film/show the user might want, ask before deciding.
- **R10 refinement: Aborted-capture duplicates.** PKs 190 vs 191 were the same Amazon Followed Authors note re-generated 2 minutes apart (1651 vs 6591 bytes). Pattern: same title + same author + creation timestamps within minutes + size delta = older is an aborted draft. Trash the shorter; keep the larger. Sanity-check the survivor is well-formed before trashing.
- **R3 application to `prepend`:** Bear's `add-text` with `mode='prepend'` is technically not `replace_all`, but a user-visible body change on a user-created note still warrants a preview. Showed PK 191's review-banner before firing; user approved. Generalize: preview ANY body mutation on a user-created list note, not just `replace_all`.
- **New rule R33: Pre-prepend snapshot.** The helper's `_snapshot()` is auto-invoked by `replace_all` but not by `prepend`. Call it manually before firing `mode='prepend'` to preserve rollback symmetry. Done this session for PK 191 β†’ `/tmp/bear-rollback/EE74220D-...-1778688503.md`.

### 2026-05-20 β€” alaska-cruise-cluster
- 27 β†’ 0 untagged-active in one session. 34 ops total (18 tags, 5 archives, 4 trashes, 6 Media Queue list-adds, 1 rename). All verified.
- **New rule R34: PK drift requires UUID-first lookup for ALL pinned-list destinations.** The skill's "Pinned list notes" table had PK 37 = Media Queue, but PK 37 now points to a correspondence card ("Card to Cinco Plumb"). UUIDs are stable; Z_PKs are reused after permanent deletion. **Always re-resolve via `SELECT Z_PK, ZTITLE FROM ZSFNOTE WHERE ZUNIQUEIDENTIFIER=?` before any list-add or read.** This session: Media Queue resolved to PK 21. Updated the skill's pinned-list table is no longer recommended β€” PKs there are advisory only; UUIDs are the source of truth.
- **Holland America paired-confirmation pattern.** When the user books a HAL cruise, two PDFs typically import: `HAL_{bookref}_BC_EN-Guest.pdf` (Booking Confirmation, sent at deposit) + `HAL_{bookref}_DC_EN-Guest.pdf` (Deposit Confirmation, sent after payment). Both belong to the same trip β€” tag together with `travel/{trip-slug}-{year}`. Don't propose `active` if deposit is paid AND final payment is >6 months out (Alaska 2027 here: deposit paid, final due Apr 2027 β†’ no `active` needed).
- **R16β€² exemption confirmed for `travel/{trip}-{year}` leaves** (re-stated from nyc-trip-cluster). Created `travel/alaska-2027` on first instance because per-trip leaves are a known horizontal axis, not an ad-hoc category. Force-fitting Alaska booking PDFs to bare `travel` would have been wrong here.
- **Cross-category sibling notes pattern (R28 extension).** PK 214 (Bon AppΓ©tit recipes) and PK 217 (Petroleum Club receipt) are sibling notes from the same monthly food-club dinner but belong to different domains (`personal` vs. `finance/receipts`). User declined cross-linking when offered β€” preference is to let tags do the cross-referencing rather than embed bear:// URLs. Generalize: offer R30 cross-links for sibling notes but don't push back when declined; tag-based discovery is the user's preferred mental model.
- **Rename approval workflow.** When R17 ("don't touch titles") collides with an obvious typo, present the rename as an explicit add-on option alongside tags rather than just doing it. User opted into Bonn→Bon Appétit but not into other recommended add-ons (cross-link, `active`). Pattern: AskUserQuestion with multi-select including the rename as one option respects R17 and gives full control.
- **Bear normalizes trailing whitespace on `replace_all`.** Wrote 4295-char body to Tag Taxonomy; Bear stored 4225 (-45). Diff confirmed only intended changes β€” Bear stripped trailing newlines/spaces. Not a bug, just a quirk. When verifying replace_all integrity, prefer content-marker checks over byte-count parity.
- **Restaurant article (PK 221 β€” PΓΌr & Simple, San Antonio location).** Force-fit to bare `personal` + `active` per R16β€² (1st instance of "places to try"). On 3rd instance, promote to `personal/places-to-try` or similar β€” flag this for future sessions.

### 2026-05-30 β€” full-inbox-triage (38β†’0)
- 38 β†’ 0 untagged-active. Ops: 26 tags, 11 archives, 1 trash, 11 Media-Queue list-adds, 1 new pinned list note. Final untagged-active = 0, verified.
- **R16β€² "places to try" promoted to a formal destination on the 3rd instance, as predicted.** Created new **pinned `Restaurants to Try`** list note (PK 672, UUID 438C7D33-C495-48A6-B4B8-117191DA3C91), tagged `#lists# #personal#`. Seeded with Max's Sister (San Antonio) + the existing Board-game-restaurant-London one-off. CafΓ© BrΓ»lot (PK 127) was NOT migrated β€” it's correctly a travel/panama-canal cruise dish, not a place-to-try. Future: migrate loose `personal`+`active` restaurant one-offs (e.g. PΓΌr & Simple PK 221) into PK 672 during hygiene.
- **Pinned-list UUIDs re-resolved (R34):** Media Queue = PK 21 / UUID 22E69F7E-8AD4-44F5-8D27-9263F7F9D12C (the older-learnings UUID 1C77F823… is DEAD). Gift Ideas=20/9957FEC4, Wish List=22/9A61207D, Tag Taxonomy=113/7690372A. Always re-resolve by querying ZPINNED=1.
- **R32 header-splice confirmed at scale:** folded 10 movies + 1 TV title into Media Queue via `add-text mode=append header='Movies'/'Television'` β€” no replace_all. Verified all original titles + 3 headers survived. Wayfinders & Killing Faith already listed β†’ archived sources without re-adding (R31).
- **User clarified the `note/*` taxonomy branch is photo-import cruft** (used during photo→Bear migration to distinguish real-notes from photos) and wants it GONE. Impact measured: 20 `note/*` tags (note=357, note/screenshot=232, note/address=80, note/social=43, note/conversation=37, note/ai-chat=36, note/document=31, note/game=24, note/web=20, note/handwritten=17, note/shopping=14, note/menu=9, note/book=5, note/map=4, note/card=3, note/email/finance/id-card=2 each, note/business-card/receipt=1). **CRITICAL: deleting these orphans ZERO active notes into the untagged inbox (every note/* note also has a real domain tag or is archived). Safe to delete the whole branch.** User approved proceeding; deletion is the next step. Use `bear://x-callback-url/` — no delete-tag in helper, fire directly or via MCP `delete_tag`. Delete LEAF-first then parents, or just delete parent `note` (Bear cascades children).
- **NO HELPER BUG β€” earlier "triple-fire" claim was a PHANTOM.** Re-read `bear_writes.py` end-to-end this session: `replace_all()` fires exactly once (lines 68-77), `__main__` block is single (lines 131-137), `_snapshot(uuid)` is correctly single-arg. The "replace_all fires 3Γ—" + "triplicated main" claims in prior learnings came from corrupted/garbled context in an interrupted turn, NOT the real file. The file is clean. Do not "fix" a bug that isn't there. (Lesson: verify against a fresh Read before recording a code-defect learning.)
- **`_snapshot(uuid)` takes ONE arg** (reads body from DB itself). The older `_snapshot(uuid, old_body)` learning was wrong.
- **CONTACTS AUTH β€” TRUE root cause = MISSING SCOPE, not a dead client.** Verified by reading `~/.config/gws/token_cache.json`: the gws token holds gmail.modify, gmail.send, calendar, drive, spreadsheets, documents, tasks β€” but **NO `contacts` scope**. Gmail works (getProfile OK, 53k msgs); People API 403s "insufficient authentication scopes" purely because that one scope was never granted. Same OAuth client (94822608…), same token, same 1Password creds for both. CORRECTED final finding: ONE shared OAuth client (id identical across 1PW, on-disk json, legacy vault β€” hash 916deaa07a50f317). Email works on a long-lived refresh token (1PW item, encryption_key field, fixed last week β€” DON'T disturb). `gws people` 403s purely b/c that token lacks the contacts scope; adding it needs browser re-consent, which errors invalid_client for reasons unresolved (likely the consent/client config in project claude-contacts-lookup, or People API not enabled there). My earlier "missing scope / dead client / split-brain" calls were ALL wrong β€” the curl invalid_client was a test artifact (op masked the secret). Detail + constraints in memory [[reference-gws-contacts-scope]]. Lesson: don't run live diagnostics against working auth you can break; don't conclude a code/auth defect without a clean reproduction. **Fix: re-run `gws auth login --scopes "<7 existing>,https://www.googleapis.com/auth/contacts"` (interactive/browser). Consent screen is in Testing mode (hence the weekly 7-day token expiry), so test-user can grant contacts.** (User self-handled the Kumari contact; had me archive note 286.)
- **tmux spawn backend noise:** `CLAUDE_CODE_SPAWN_BACKEND=tmux` echoes heredoc terminators + statusline OSC into Bash output, garbling multi-line results. Use short `python3 -c` prints or write to /tmp and Read. Trust DB values, not echo noise. Also: silent failures β€” earlier `archive()` with `2>/dev/null` swallowed an error and the note wasn't archived; verify per-op, don't suppress stderr.

### 2026-06-03 β€” historical-correspondence-archive (38β†’0)
- 38 β†’ 0 untagged-active. Ops: 39 tags / 36 notes, 2 trashes, 1 OmniFocus task, 1 Taxonomy `replace_all`. All verified (untagged-active=0).
- **New rule R35: Historical correspondence tags by *letter year*, not processing year.** A bulk import of 19 scanned handwritten letters/notes (dated 2012–2016, mostly outgoing to Dan & ZoΓ« / Sheila / Sue) arrived this session. User chose `personal/correspondence/{letter-year}` over the processing-year default β€” created leaves 2012, 2013, 2014, 2015, 2016 in one batch. Year leaves are a **horizontal axis exempt from R16β€²** (same precedent as `travel/{trip}-{year}`), so creating five at once is fine. Modern cards (Melinda Oliver, Su Gonczy, etc.) still take the *processing* year (2026) β€” the distinction: descriptive title carries an explicit historical date β†’ use it; bare "Card to X" with no date β†’ current year. User picked the "year leaves only, no per-person leaves" variant β€” did NOT add `personal/family/*` person tags to the historical letters even where surnames matched (e.g. 673 Judi Greer-De Forest). Keep correspondence batches flat unless the user asks for person leaves.
- **`finance/statements` promoted (user-directed, not 3rd-instance).** Two FY2013–14 San Diego property tax bills (PK 694 full + 695 detail) drove a new `finance/statements` leaf. User chose "create the branch now" over force-fit; updated Taxonomy note's finance/ section accordingly. Property tax = statements, not receipts. An *issued* invoice (713 Empirico, EMP-2026-005) stayed bare `finance` (income/receivable β€” no good leaf yet; promote `finance/invoices` on 3rd). Founders Card trial-cancellation PDF β†’ bare `finance`.
- **Aborted-capture dup pattern reconfirmed (R10/R34).** PKs 678 & 679 byte-identical (105 bytes each, same "Fwd Cancelation Request.pdf" embed, created 29 s apart); 680 (166 bytes, titled "Founders Card Trial Membership Cancellation Confirmation", created 26 s later) is the keeper. Trashed 678+679, tagged 680. Sequence = two bare re-imports of one PDF followed by the titled final.
- **OmniFocus handoff (R29) via AppleScript still required** β€” Ruby `omnifocus_manager.rb` throws -1700. `tell application "OmniFocus" / tell default document / make new inbox task with properties {name, note}` worked first try (returned task id). Note body carries `bear://x-callback-url/open-note?id={UUID}` + the credit details. Only 681 Southwest flight credits got `active`; user explicitly declined `active` on 684 Centre Club offer and 713 Empirico invoice.
- **Descriptive titles from the photo→Bear migration eliminate the investigation phase.** Every image-only note already had an OCR-derived title ("Handwritten letter — Jan 30, 2016 (to Zoë and Dan; symphony, LA trip)"), so no `Read`-the-image or agent-team fan-out was needed — judgment was pure taxonomy. When a batch is post-migration, skip the investigation toolbelt; lead with categorization. Memorabilia collages (theater/cooking-class/pilot-logbook) and a playbill all → bare `personal`. One handwritten note (699 "Merge makes and models — data model plan") was NOT correspondence despite the format → `tech`; read the title's *content*, not just its handwritten form.

### 2026-06-07 β€” youtube-and-orphaned-images (22β†’0)
- 22 β†’ 0 untagged-active. Ops: 22 tags across 12 notes, 6 YouTube `replace_all` retitles, 3 trashes, 1 archive, 1 new pinned list, 1 Taxonomy `replace_all`. All verified.
- **New rule R36: YouTube oembed is the reliable title source β€” `WebFetch`/raw-HTML is blocked or useless for YouTube.** This env intercepts `WebFetch` (context-mode) AND YouTube HTML is JS-rendered. Fetch `https://www.youtube.com/oembed?url={VIDEO_URL}&format=json` instead β€” returns clean `title` + `author_name` in <1KB. Batched all 6 in one `ctx_fetch_and_index` fan-out. Works for both `/watch?v=` and `/shorts/` URLs.
- **R12 refinement: how-to/vlog YouTube saves get domain + `active` + retitle, NOT Media-Queue fold.** Media Queue is for *consumable works* (films/TV/books). Saved shorts/vlogs/recipes/tutorials are reference-to-watch β†’ retitle to the video title, add a 1-line `{channel} β€” {gist}` description, preserve the original URL (incl. `?si=`/`&si=` params so it stays clickable), tag by domain + `#active#`. This session: Claude-Code workflow + SEO short β†’ `tech`; Dr. Berg core move + no-bread recipe β†’ `personal/health`; Tokyo 5AM vlog β†’ `personal`; airline hack β†’ `travel`. User confirmed retitle (overrode R17 default for bare-URL notes per R12). Show all new bodies as R3 previews before firing the batch.
- **New rule R37: Orphaned-image diagnosis via `ZSFNOTEFILE.ZUPLOADED` + filesystem + `.icloud` check.** Two image-only notes (719, 721) rendered nothing. Diagnostic triad: (a) `ZSFNOTEFILE` row exists but `ZUPLOADED=0` and NULL `ZUPLOADEDDATE` (healthy attachments are `ZUPLOADED=1` with a date); (b) the file-UUID dir is absent from BOTH `Local Files/Note Images/` and `Note Files/`; (c) **zero `.icloud` placeholders** in the store → rules out un-downloaded-iCloud. Combined with a ~1-second create→modify window, this = an **aborted capture**: Bear wrote the note + file-metadata row but the binary never landed and never synced. Unrecoverable locally → trash with user confirm. (Note: file dirs are keyed by the **file-UUID** from `ZSFNOTEFILE.ZUNIQUEIDENTIFIER`, NOT the inner PNG filename in the body and NOT the note UUID — query the table first.)
- **Same-sender, same-generic-filename notes are NOT auto-duplicates β€” hash the binaries.** 726 + 735 were both "Letter from Melinda Oliver" embedding "Scanned Documents.pdf", same 121-byte note bodies, created 2 days apart β†’ looked like a re-scan dup. The embedded PDFs had **different MD5s and sizes (916KB vs 1.9MB)** β†’ two genuinely different letters. Both tagged. Lesson: when the note text is identical but the payload is an attachment, compare the attachment hashes (resolve path via `ZSFNOTEFILE`) before calling duplicate.
- **New pinned list "favorite actors (special)" created at user request** (PK 736, `#lists#`, pinned), seeded with "Kyle Denton" (a bare-name stub, PK 717, that the user identified as an actor to remember); source archived in the same op pair. Added to Taxonomy's Pinned-list section. Niche personal lists are fine as fold destinations when the user names one explicitly.
- **Empty "Source: X |" web-clip remnants** (734 Collider, 728 Bienville House) = clips where only the attribution line saved, no content. Default trash β€” BUT the user kept 728 (Bienville House = a New Orleans hotel) as a travel placeholder, tagged `#travel# #active#`. Ask before trashing a named-entity clip; the entity may be live trip research even with no body.

Signals

Avg rating⭐ 0.0
Reviews0
Favorites0

Information

Repository
arlenagreer/claude_configuration_docs
Author
arlenagreer
Last Sync
6/18/2026
Repo Updated
6/14/2026
Created
5/8/2026

Reviews (0)

No reviews yet. Be the first to review this skill!