Claude
Skills
Sign in
Back

digest

Included with Lifetime
$97 forever

Generate a themed weekly digest from Obsidian ReadItLater bookmarks. Use this skill when the user runs /readitlater-digest:digest or asks to process bookmarks, create a reading digest, summarize saved articles, or consolidate ReadItLater files. Also trigger on cron/loop invocations targeting bookmark processing.

General

What this skill does


# ReadItLater Weekly Digest

Generate a themed digest from unprocessed Obsidian ReadItLater bookmarks. Designed for automated runs via cron or `/loop`.

## Configuration

Read settings from `.claude/readitlater-digest.local.md`. If it doesn't exist, prompt the user to create one using the template below, then stop.

**Required settings** (YAML frontmatter):

| Field | Default | Description |
|-------|---------|-------------|
| `vault_path` | `/Volumes/Verbatim-Vi560-Media/Development/notes/scratchpad` | Obsidian vault root |
| `inbox_folder` | `ReadItLater` | Folder where ReadItLater saves bookmarks |
| `digest_folder` | `Digests` | Folder for generated digests |
| `archive_folder` | `<inbox_folder>/Archive` | Where processed bookmarks get moved (default: `<inbox_folder>/Archive`) |

Derived paths:
- `db_path` = `<vault_path>/.readitlater-digest.db`
- `inbox_path` = `<vault_path>/<inbox_folder>`
- `digest_path` = `<vault_path>/<digest_folder>`
- `archive_path` = `<vault_path>/<archive_folder>` (default: `<inbox_path>/Archive`)

**If `archive_folder` is not set**, derive it as `<inbox_folder>/Archive`.

## Resolving `bun`

Before running any script, resolve the bun executable once:

```bash
BUN=$(command -v bun 2>/dev/null || echo "$HOME/.bun/bin/bun")
```

Use `$BUN` in place of `bun` throughout all subsequent script invocations. This prevents silent failures in cron/non-interactive shells where `.zshrc` is not sourced.

## Pipeline

Run these steps in order. If `--dry-run` is passed as an argument, stop after Step 2 and report what would be digested.

### Step 0: Pre-check for existing digest

Before starting the pipeline, check whether a digest already exists for the current week:

```bash
sqlite3 "<db_path>" \
  "SELECT id, file_path FROM digests WHERE week_start = '<week_start>' AND week_end = '<week_end>'"
```

If a row is returned, **abort immediately** and report: "A digest already exists for <week_start> to <week_end>: <file_path>. Pass --force to regenerate." Do not proceed unless the user explicitly confirms.

### Step 1: Initialize database and validate paths

```bash
$BUN run ${CLAUDE_PLUGIN_ROOT}/scripts/init-db.ts --db-path "<db_path>"
```

This is idempotent — safe to run every time.

Also ensure the archive path exists:

```bash
mkdir -p "<archive_path>"
```

### Step 2: Scan inbox for new bookmarks

```bash
$BUN run ${CLAUDE_PLUGIN_ROOT}/scripts/scan-bookmarks.ts \
  --inbox-path "<inbox_path>" \
  --db-path "<db_path>"
```

The script outputs JSON with `new`, `duplicates`, `already_tracked`, and `errors` fields.

If there are **zero new + zero unprocessed** bookmarks, report "No unprocessed bookmarks" and stop. Do not generate an empty digest.

If `--dry-run`, print the scan results and stop here.

### Step 3: Read and enrich bookmark content

1. Query the database or use the scan output to identify all `unprocessed` bookmarks.
2. **Batch-read all bookmark files in one pass** — run a single shell command to read all inbox markdown files at once rather than one file per invocation:

   ```bash
   cat "<inbox_path>"/*.md "<inbox_path>"/**/*.md 2>/dev/null
   ```

   Or use the Read tool on each file in a single parallel batch rather than sequentially.

3. **Classify bookmarks before enrichment.** After reading, separate bookmarks into two groups:
   - **Resolvable**: file body has ≥50 words of content (excluding frontmatter), or has a fetchable URL that returns content.
   - **Unresolvable**: fewer than 50 words of body content AND the URL is a short-link, mobile redirect, or returns no extractable content (e.g., TikTok, Reddit mobile, Google share links). Mark these for the appendix (see Step 4).

4. **Content enrichment** — for resolvable bookmarks that are thin (<200 words), enrich using this sequence:
   a. **Check qurl first**: `qurl get "<url>"` — if exit 0, use the returned content directly and skip `WebFetch`.
   b. **Fetch if not cached**: fetch with `WebFetch`. If the fetch fails or returns little content, treat as unresolvable.
   c. **Index after fetch**: `echo "<fetched_content>" | qurl add "<url>" --source readitlater --tags "<inferred_topic>"`.
   Run fetches and qurl checks concurrently where possible.

5. Extract **substantially more content** per bookmark than a bare summary — capture key arguments, notable quotes, specific data points, and the author's main thesis. The goal is enough material to write informed editorial commentary, not just a blurb.

### Step 4: Cluster by theme and find the narrative

1. Analyze all **resolvable** bookmarks together and identify **3-7 natural themes**:
   - Themes should be specific and descriptive (e.g., "Agentic Engineering Patterns & Multi-Agent Architectures" not "AI")
   - A bookmark can appear in multiple themes if it genuinely spans topics
   - Group stragglers under a casual catch-all section (e.g., "Quick Saves", "Miscellaneous") at the end
2. **Unresolvable bookmarks** are collected separately and appended as an "Unresolvable Links" section (see template below). Do not attempt to write editorial commentary for these — a single sentence noting the link is sufficient.
3. **Find the throughline.** Identify the overarching narrative that connects the week's themes — a single sentence or idea that ties the reading together. This becomes the digest title and opening paragraph.

### Step 5: Generate the digest note

Determine week boundaries (default: Monday-Sunday of the current week, or use `--week YYYY-MM-DD` to specify the Monday).

**Week label accuracy**: The `week` frontmatter field reflects the calendar week boundaries used to select bookmarks (e.g., `2026-03-30 to 2026-04-05`). Additionally, include a `date_range` field showing the actual span of bookmark `date_saved` values (e.g., `2026-03-24 to 2026-03-29`). If bookmarks span multiple weeks, use the most recent Monday-Sunday as `week` but always set `date_range` to the actual bookmark dates.

Write the digest to: `<digest_path>/Digest — <week_start> to <week_end>.md`

**Template:**

```markdown
---
type: digest
date_generated: <ISO date>
week: <week_start> to <week_end>
date_range: <earliest_bookmark_date> to <latest_bookmark_date>
bookmark_count: <count>
themes:
  - <theme 1>
  - <theme 2>
---

# <Creative Title>

<Opening paragraph: 2-4 sentences establishing the throughline — what connected this week's reading, why it matters, and the editorial lens.>

## <Theme Name — evocative, not just descriptive>

<Editorial prose weaving multiple bookmarks into a narrative. Link to sources inline using [display text](url) markdown links. Discuss, compare, and comment on the articles rather than listing them. Each paragraph should read like a newsletter essay — opinionated, specific, and useful. Mention what's interesting, what's surprising, what connects to other reads. If a bookmark's content was thin or inaccessible, acknowledge it naturally in the prose (e.g., "though the full content wasn't extractable from the bookmark").>

<Continue with more paragraphs as needed for the theme. Multiple bookmarks per paragraph when they relate.>

## <Next Theme>

...

## <Catch-all section: "Quick Saves" or similar>

<Brief mentions of bookmarks that don't warrant full commentary but are worth noting. One or two sentences each, still in prose form.>

## Unresolvable Links

<Include this section only if there were unresolvable bookmarks. List each as a bullet with title and URL. No editorial commentary — just the link.>

- [<title>](<url>)
- ...

---

<Closing reflection: 1-2 sentences reflecting on the week's reading as a whole — a parting thought, not a summary.>

*Generated by ReadItLater Digest*
```

**Writing style rules:**
- **Editorial voice**: Write as a thoughtful reader sharing what they found interesting, not a summarization engine. Use first person sparingly ("my favorite", "what strikes me").
- **Inline links**: Use `[display text](url)` markdown links woven into sentences — never structured link blocks.
- **No per-bookma

Related in General