# Daily Digest — Execution Instructions

You are a Claude Code agent. Your job is to generate a daily digest from Product Hunt and Reddit.

---

## Pre-flight Checklist

Before starting any work, verify:

- [ ] **VPN connected**: `sg nordvpn -c "nordvpn status"` — Reddit blocks VPS IPs
- [ ] **Checkpoint exists?**: Check `digest-archive/{date}/checkpoint.md` to resume or start fresh
- [ ] **You understand**: Write to checkpoint after EVERY action (never keep data only in memory)
- [ ] **You understand**: Discover content ONLY from primary sources (see below)

---

## Primary Sources vs Verification Tools

**PRIMARY SOURCES (where you DISCOVER content):**
1. **Product Hunt** → `./DIGESTS/0-PRODUCTHUNT/fetch-producthunt.sh {date}`
2. **Reddit** → Reddit MCP tools (`browse_subreddit`, `get_post_details`)

**VERIFICATION TOOLS (only for validation/enrichment):**
- `WebSearch` → Verify URLs, find official sources, get context on items found in primary sources
- `WebFetch` → Read product websites, articles linked from Reddit posts

**NEVER use WebSearch to discover/find new items.** WebSearch is ONLY for:
- Verifying a URL is correct (especially Twitter/X links)
- Finding the official website for a product found on PH/Reddit
- Getting additional context about a Reddit post topic
- Finding the correct article URL when a Reddit link is broken

---

## Policies

### Write-As-You-Go Protocol

**NEVER keep data only in memory. After EVERY action that produces data:**

1. **DO** the action (fetch, search, analyze)
2. **WRITE** results to `digest-archive/{date}/checkpoint.md`
3. **VERIFY** by reading the checkpoint file back
4. **THEN** continue to next step

This ensures:
- If context runs out, checkpoint.md has all data
- Final HTML generation uses correct, persisted URLs
- Each step is atomic and recoverable

### Content Freshness

**Only include recent content:**
- Product Hunt: Products launched in the last 7 days
- Reddit: Posts from the last 24-48 hours (use "top of day/week")
- News/announcements: From the last 7 days
- If a product/model was released more than 7 days ago, it's stale — skip it

*(Note: This is different from the "Deduplication Window" in step 0.7, which scans the last 7 days of YOUR digests to avoid repeating items.)*

### Item Count Requirements

**Minimum 5 items per source, optimally 10:**
- Product Hunt: 5-10 items (be generous with interesting products)
- AI-LLMs: 5-10 items
- GenAI-Media: 3-5 items (smaller section, can have fewer)
- Apps-Software: 5-10 items (be VERY lenient here — include almost everything)

**Total digest: 15-30 items** — aim for ~20 when content is good.

Do NOT be overly selective. If something is remotely interesting and matches the user's interests, INCLUDE IT.

### URL Requirements

- **ALWAYS save specific URLs** — Not generic profiles, but specific content links
- **NEVER use generic profile URLs** like `https://x.com/username`
- **ALWAYS use specific content URLs** like `https://x.com/username/status/123456789`
- All Product Hunt items link to product websites, not PH pages
- All Reddit items link to primary sources, not Reddit threads

### WebFetch Timeout Policy

**Set a 15-second timeout on all WebFetch calls** to prevent stalls:
- If a fetch times out or fails, note it in checkpoint and move on
- Use WebSearch as fallback for product info when WebFetch fails
- Don't block on slow websites — move on and use available data

---

## File Structure

```
digest-archive/
└── 2025-12-30/              ← ISO date format (YYYY-MM-DD)
    ├── checkpoint.md        ← ALL state and data in ONE file
    └── index.php            ← Final output (PHP for feedback form)

DIGESTS/
├── 0-PRODUCTHUNT/
│   ├── INTERESTS.md         ← What to look for
│   ├── MEMORY.md            ← Personal context
│   └── fetch-producthunt.sh ← Fetch script
├── 1-AI-LLMS/
│   ├── INTERESTS.md
│   ├── MEMORY.md
│   └── SUBREDDITS.md        ← List of subreddits to fetch
├── 2-GENAI-MEDIA/
│   └── ...
└── 3-APPS-SOFTWARE/
    └── ...

WEB/
├── template.php             ← PHP template (read-only reference)
├── css/
├── js/
└── assets/

logs/
├── raw/                     ← Raw orchestrator + Claude attempt logs
└── past-logs/               ← Structured markdown reports per day

COMPLETED-DAYS.md            ← Append-only ledger of completed digests (ISO dates)
.orchestrator-ack-YYYY-MM-DD ← Created by orchestrator after successful completion
run-digest-orchestrator.sh   ← Nightly automation script (runs via systemd timer)
```

---

## Reddit MCP Commands

**Browse a subreddit:**
```
mcp__reddit-mcp-buddy__browse_subreddit
  - subreddit: "openai" (without r/ prefix)
  - sort: "hot" | "new" | "top" | "rising" | "controversial"
  - time: "hour" | "day" | "week" | "month" | "year" | "all" (for top/controversial)
  - limit: 25 (default, max 100)
```

**Get post with comments:**
```
mcp__reddit-mcp-buddy__get_post_details
  - post_id: "1abc2d3" (from the post URL)
  - subreddit: "openai" (more efficient if provided)
  - comment_limit: 20 (default)
  - max_top_comments: 5 (default)
  - comment_sort: "best" | "top" | "new" | "controversial"
```

**Search Reddit:**
```
mcp__reddit-mcp-buddy__search_reddit
  - query: "search terms"
  - subreddits: ["openai", "LocalLLaMA"] (optional, array)
  - sort: "relevance" | "hot" | "top" | "new" | "comments"
  - time: "hour" | "day" | "week" | "month" | "year" | "all"
  - limit: 25
```

---

## Step 0: Initialize

### 0.1 Verify Environment

**Check VPN status:**
```bash
sg nordvpn -c "nordvpn status"
```

If not connected:
```bash
sg nordvpn -c "nordvpn connect"
```

If you get blocked during fetching (error: "Cannot access r/subreddit"), switch to a new node:
```bash
sg nordvpn -c "nordvpn disconnect" && sg nordvpn -c "nordvpn connect"
```

### 0.2 Get Today's Date
```bash
date +%Y-%m-%d
```

### 0.3 Create Working Directory
```bash
mkdir -p digest-archive/{date}
```

### 0.4 Check Existing State
```bash
ls digest-archive/{date}/checkpoint.md
```

- **File exists** → Read it, find `phase:` line, resume from there
- **File doesn't exist** → Create checkpoint.md with initial header, start fresh

### 0.5 Create Initial Checkpoint (if new)

Write to `digest-archive/{date}/checkpoint.md`:
```markdown
# Digest: {date}

## Status
phase: starting
updated: {timestamp}

---

## Previous Digests (Last 7 Days)
<!-- Populated in step 0.7 -->

### Developing Stories
<!-- Note any ongoing stories to watch for follow-ups -->

---
```

### 0.6 Read Configuration Files

Read these files and keep in memory for filtering decisions:
- `DIGESTS/0-PRODUCTHUNT/INTERESTS.md`
- `DIGESTS/0-PRODUCTHUNT/MEMORY.md`
- `DIGESTS/1-AI-LLMS/INTERESTS.md`
- `DIGESTS/1-AI-LLMS/MEMORY.md`
- `DIGESTS/1-AI-LLMS/SUBREDDITS.md`
- `DIGESTS/2-GENAI-MEDIA/INTERESTS.md`
- `DIGESTS/2-GENAI-MEDIA/MEMORY.md`
- `DIGESTS/2-GENAI-MEDIA/SUBREDDITS.md`
- `DIGESTS/3-APPS-SOFTWARE/INTERESTS.md`
- `DIGESTS/3-APPS-SOFTWARE/MEMORY.md`
- `DIGESTS/3-APPS-SOFTWARE/SUBREDDITS.md`

### 0.7 Scan Previous Digests (Deduplication & Continuity)

**Before fetching any content**, scan the last 7 days of digests to:
1. **Avoid duplicates** — Don't include items already covered
2. **Enable continuity** — Connect developing stories across days

**Steps:**

1. List recent digest directories:
   ```bash
   ls -d digest-archive/2025-*/ | tail -7
   ```

2. For each existing `index.php`, extract all `href` URLs:
   ```bash
   grep -oP 'href="\K[^"]+' digest-archive/{date}/index.php
   ```

3. **Write to checkpoint** immediately after scanning:
   ```markdown
   ## Previous Digests (Last 7 Days)

   ### 2025-12-30
   - https://briefmymeeting.com
   - https://www.resemble.ai/chatterbox-turbo/
   - https://x.com/bcherny/status/2004897269674639461
   [... all URLs from that day ...]

   ### 2025-12-29
   [... URLs ...]

   ### Developing Stories (from last 7 days)
   - **Claude Code adoption** — Covered 12/30 (Boris Cherny 100% AI code). Watch for follow-ups.
   - **Tencent open source releases** — HY-Motion, HY-MT1.5 covered 12/30. More releases possible.
   ```

   *(Note: This is SHORT-TERM context from recent digests. For LONG-TERM tracking, see `MEMORY.md` files updated in Step 7.)*

4. **During filtering**, check each candidate against previous URLs:
   - **Exact URL match** → SKIP (already covered)
   - **Same product/topic, no new info** → SKIP (don't repeat)
   - **Same topic WITH significant new development** → INCLUDE as follow-up
   - **Completely new** → INCLUDE normally

**INCLUDE as follow-up (adds real value):**
- New version, update, or release
- Major discovery or breakthrough
- High-quality discussion with genuine insights
- Official response, correction, or clarification
- Significant community findings (benchmarks, workarounds, use cases)
- Business news (acquisition, funding, partnerships)
- Expert analysis or deep-dive that adds context

**SKIP (low quality or redundant):**
- Same information rehashed with no new insight
- Low-effort opinions or complaints
- Reposts or cross-posts of identical content
- Hype without substance
- Minor patch notes nobody cares about

**Quality over type:** A thoughtful discussion thread CAN be a valid follow-up if it surfaces genuinely new insights. The test is: "Does this add something the reader didn't get from the previous coverage?"

**When including a follow-up, use these prefixes in the description:**
- "Update: {what's new}..."
- "Following yesterday's coverage of {X}, {new development}..."

---

## Step 1: Product Hunt

### 1.1 Fetch Products

Run the fetch script:
```bash
./DIGESTS/0-PRODUCTHUNT/fetch-producthunt.sh {date}
```

This returns markdown with:
- Top 20 products sorted by votes
- Product details (ID, name, tagline, description, votes, URL, website, thumbnail)
- Top 10 comments for each product

### 1.2 Save Raw Data to Checkpoint

**IMMEDIATELY** after fetching, append to checkpoint.md:

```markdown
## Source 0: Product Hunt

### Fetch
- [x] Fetched 20 products at {timestamp}

### Raw Data
| Rank | ID | Name | Tagline | Votes | PH_URL | Website |
|------|-----|------|---------|-------|--------|---------|
| 1 | 789012 | ProductName | Short tagline | 425 | https://producthunt.com/posts/productname | https://product.com |
| 2 | ... | ... | ... | ... | ... | ... |
```

**VERIFY**: Read checkpoint.md to confirm data is saved before continuing.

### 1.3 Initial Filter

Review all 20 products against `INTERESTS.md`:
- Look for: automation tools, power user tools, macOS apps, hardware, AI tools, self-hosted
- Skip: note apps (unless novel), generic project management, social media tools, crypto, Windows-only

Append to checkpoint.md:
```markdown
### Initial Filter
| ID | Name | Decision | Reason |
|----|------|----------|--------|
| 789012 | ProductName | CANDIDATE | Matches: AI tool |
| 789013 | OtherApp | SKIP | Note app, nothing new vs Obsidian |
```

### 1.4 Deep Analysis (per candidate)

For each CANDIDATE:

1. **Website Analysis**: Use `WebFetch` on the product website
   - What exactly does it do?
   - Pricing model?
   - Technical details?

2. **Context Search**: Use `WebSearch` to verify/enrich (not discover)
   - Is this new or a re-launch?
   - Any reviews or discussions?

3. **Extract URLs**: Find and save:
   - Product website URL
   - Product Hunt page URL
   - Any relevant links (GitHub, docs, etc.)

4. **Decision**: INCLUDE or DISCARD

**After EACH candidate**, append to checkpoint.md:
```markdown
### Analyzed: ProductName (ID: 789012)
- decision: INCLUDE
- website: https://product.com
- producthunt: https://producthunt.com/posts/productname
- github: https://github.com/org/repo (if found)
- votes: 425
- summary: |
    One paragraph describing what it does and why it's interesting.
    Include pricing, technical details, and unique features.
```

### 1.5 Mark Source Complete

Update checkpoint.md:
```markdown
### Product Hunt Complete
- candidates_analyzed: 5
- included: 2
- phase: source-0-complete
```

---

## Step 2: Reddit — AI & LLMs (Source 1)

### 2.1 Fetch Posts

Read `DIGESTS/1-AI-LLMS/SUBREDDITS.md` for the list of subreddits.

For each subreddit, use Reddit MCP `browse_subreddit` with:
```json
{
  "subreddit": "{subreddit_name}",
  "sort": "top",
  "time": "day",
  "limit": 25
}
```

### 2.2 Save Raw Data to Checkpoint

**IMMEDIATELY** after each subreddit fetch, append to checkpoint.md:

```markdown
## Source 1: AI-LLMs

### Fetch: r/{subreddit}
- [x] Fetched {n} posts at {timestamp}

| ID | Title | Score | URL | External_URL | Has_Image | Created_UTC |
|----|-------|-------|-----|--------------|-----------|-------------|
| 1abc2d | GPT-5 solved math problem | 2847 | https://reddit.com/r/openai/comments/1abc2d | https://x.com/user/status/123 | no | 1735257600 |
```

**VERIFY**: Read checkpoint.md to confirm before fetching next subreddit.

### 2.3 Initial Filter

After fetching ALL subreddits for this source, review posts against `INTERESTS.md`:
- Look for: new model releases, computer use, MCPs, research breakthroughs, societal impacts
- Skip: memes, basic questions, drama, speculation, pricing complaints, wrapper products

Append to checkpoint.md:
```markdown
### Initial Filter
| ID | Subreddit | Title | Decision | Reason |
|----|-----------|-------|----------|--------|
| 1abc2d | openai | GPT-5 solved math problem | CANDIDATE | Research breakthrough |
| 2def3e | openai | ChatGPT is down | SKIP | Outage complaint |
```

### 2.4 Deep Analysis (per candidate)

For each CANDIDATE:

1. **Images**: If `has_image: yes`, the content is often there
   - Analyze the image - extract text, data, benchmarks
   - Many posts have vague titles but rich image content

2. **External Links**: If post has external URL
   - Use `WebFetch` to get the content
   - Summarize key points

3. **Comments**: Use `get_post_details` with:
   ```json
   {
     "post_id": "1abc2d",
     "subreddit": "openai",
     "comment_limit": 25,
     "max_top_comments": 10
   }
   ```
   Read top comments for context, sentiment, and corrections.

4. **Context Search**: Use `WebSearch` to verify/enrich (not discover)
   - Product announcements
   - News coverage
   - Official sources

5. **Extract URLs**: This is critical for final output
   - **Primary URL**: The most relevant specific link
   - **Reddit URL**: Full permalink
   - **Source URLs**: ArXiv papers, GitHub repos, official announcements

6. **Decision**: INCLUDE or DISCARD

**After EACH candidate**, append to checkpoint.md:
```markdown
### Analyzed: GPT-5 solved math problem (ID: 1abc2d)
- decision: INCLUDE
- subreddit: openai
- score: 2847
- urls:
    primary: https://x.com/gaborcselle/status/1872749683012384915
    reddit: https://reddit.com/r/openai/comments/1abc2d/gpt5_solved_math_problem
    arxiv: https://arxiv.org/abs/2312.xxxxx
- summary: |
    GPT-5 autonomously solved an open problem in enumerative geometry.
    First AI to solve a previously unsolved mathematical conjecture
    without human guidance. Verified by mathematicians at Stanford.
- card_type: featured
```

**Card types:**
- `featured` — Major news, use sparingly (1 per section max)
- `link` — Standard items
- `compact` — Quick hits, minor updates

### 2.5 Mark Source Complete

Update checkpoint.md:
```markdown
### AI-LLMs Complete
- subreddits_fetched: 4
- candidates_analyzed: 6
- included: 3
- phase: source-1-complete
```

---

## Step 3: Reddit — GenAI & Media (Source 2)

Follow the same pattern as Step 2, using:
- Subreddits from `DIGESTS/2-GENAI-MEDIA/SUBREDDITS.md`
- Filter against `DIGESTS/2-GENAI-MEDIA/INTERESTS.md`:
  - Look for: image/video generation models, workflows for graphics, practical applications
  - Skip: generic art posts, price complaints, basic help questions
- Section header in checkpoint: `## Source 2: GenAI-Media`

---

## Step 4: Reddit — Apps & Software (Source 3)

Follow the same pattern as Step 2, using:
- Subreddits from `DIGESTS/3-APPS-SOFTWARE/SUBREDDITS.md`
- Filter against `DIGESTS/3-APPS-SOFTWARE/INTERESTS.md`:
  - Look for: macOS apps, self-hosted solutions, CLI tools, power user features
  - Skip: games, Windows-only, Android-only, apps already in MEMORY.md
- Check `DIGESTS/3-APPS-SOFTWARE/MEMORY.md` — extensive list of installed apps
  - Don't recommend apps they already have
  - Compare new apps against their current stack
- Section header in checkpoint: `## Source 3: Apps-Software`

**IMPORTANT: Be VERY lenient with this section!**
- The user loves discovering apps — include almost everything that's not garbage
- Include: macOS utilities, self-hosted tools, CLI tools, side projects, new apps
- Even if something isn't groundbreaking, if it's useful and well-made, INCLUDE IT
- The bar is LOW — only skip truly irrelevant or low-quality items
- When in doubt, INCLUDE IT
- *(See Item Count Requirements in Policies for targets)*

---

## Step 5: Final Selection

### 5.1 Review All Included Items

Read checkpoint.md and list all items with `decision: INCLUDE`.

### 5.2 Merge Duplicates

If multiple posts cover the same topic:
- Consolidate into a single entry
- Use the best information from all sources
- Note which subreddits covered it

### 5.3 Select Final Items

From ALL sources combined, prioritize:
1. Freshness (recent content only)
2. Relevance to interests
3. Novelty of information

Be generous — if it's remotely interesting, include it.
*(See Item Count Requirements in Policies for targets)*

### 5.4 Save Final Selection to Checkpoint

```markdown
## Final Selection

Total items: 5

### Item 1: GPT-5 Math Breakthrough
- source: AI-LLMs
- card_type: featured
- urls:
    primary: https://x.com/gaborcselle/status/1872749683012384915
    reddit: https://reddit.com/r/openai/comments/1abc2d
- title: GPT-5 Solves Open Math Problem Autonomously
- description: |
    First AI to solve a previously unsolved mathematical conjecture.
    GPT-5 autonomously proved a result in enumerative geometry that
    human mathematicians had been unable to solve.
- meta: x.com · r/openai

### Item 2: Alpie Core
- source: Product Hunt
- card_type: ph
- urls:
    primary: https://169pi.ai
    producthunt: https://producthunt.com/posts/alpie-core
- title: Alpie Core — 4-bit Reasoning Model
- tagline: 32B model that runs on consumer GPUs
- description: |
    Open source 4-bit quantized model. Apache 2.0 license.
    Runs on 16-24GB VRAM. Competitive with Claude 3.5 Sonnet.
- votes: 187
- domain: 169pi.ai

[... more items ...]
```

Update phase:
```markdown
phase: selection-complete
```

---

## Step 6: Generate HTML

### 6.1 Read Template

Read `WEB/template.php` for structure reference.

### 6.2 Generate HTML

Using the Final Selection from checkpoint.md, generate `digest-archive/{date}/index.php`.

**Structure:**
```php
<?php
// Feedback form handler - saves suggestions to markdown file
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['suggestion'])) {
    $suggestion = htmlspecialchars(trim($_POST['suggestion']));
    $digestDate = basename(__DIR__);
    $timestamp = date('Y-m-d H:i:s');

    $entry = "\n## From digest: $digestDate\n";
    $entry .= "**Submitted:** $timestamp\n\n";
    $entry .= "$suggestion\n\n---\n";

    // Path: from digest-archive/date/ to project root
    file_put_contents(__DIR__ . '/../../SUGGESTIONS-FROM-USER.MD', $entry, FILE_APPEND | LOCK_EX);
    $submitted = true;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Digest — {Month} {Day}, {Year}</title>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Figtree:wght@300;400;500;600&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="../../WEB/css/styles.css">
</head>
<body>
    <div class="container">
        <div class="main-card">
            <!-- Header -->
            <header class="page-header content-item">
                <span class="page-header__date">{Month} {Day}, {Year}</span>
                <span class="page-header__credits">AI-DIGEST BY MAURO SICARD</span>
            </header>

            <!-- Product Hunt Section (if items) -->
            <!-- Reddit AI-LLMs Section (if items) -->
            <!-- Reddit GenAI-Media Section (if items) -->
            <!-- Reddit Apps-Software Section (if items) -->

            <!-- Feedback Form -->
            <?php if (!empty($submitted)): ?>
                <div class="feedback feedback--success content-item" style="text-align: center; padding: 2rem;">
                    <div style="font-size: 2.5rem; margin-bottom: 0.5rem;">&#10003;</div>
                    <p style="margin: 0; font-weight: 500;">Thanks! Your suggestion has been saved.</p>
                    <p style="margin: 0.5rem 0 0; opacity: 0.7; font-size: 0.875rem;">I'll review it for tomorrow's digest.</p>
                </div>
            <?php else: ?>
                <form method="POST" class="feedback content-item" data-feedback>
                    <button type="button" class="feedback__trigger" data-feedback-trigger>
                        Tell me what to change for tomorrow
                    </button>
                    <div class="feedback__content" data-feedback-content>
                        <textarea name="suggestion" class="feedback__textarea" placeholder="What would you like me to change? More of something, less of another, different topics..."></textarea>
                        <div class="feedback__actions">
                            <button type="button" class="btn btn--secondary" data-feedback-cancel>Cancel</button>
                            <button type="submit" class="btn btn--primary">Send</button>
                        </div>
                    </div>
                </form>
            <?php endif; ?>
        </div>
    </div>
    <script src="../../WEB/js/app.js"></script>
</body>
</html>
```

### 6.3 Card Templates

**Product Hunt Card:**
```html
<a href="{urls.primary}" class="card card--ph content-item">
    <img class="card__favicon" data-size="32" alt="">
    <div class="card__content">
        <span class="card__title">{name} — {tagline}</span>
        <span class="card__desc">{description}</span>
        <div class="card--ph__meta">
            <span class="card--ph__votes">▲ {votes}</span>
            <span>·</span>
            <span>{domain}</span>
        </div>
    </div>
</a>
```

**Featured Card (Reddit):**
```html
<a href="{urls.primary}" class="card card--featured content-item">
    <div class="card--featured__header">
        <img class="card__favicon" data-size="28" alt="">
        <span class="card--featured__title">{title}</span>
    </div>
    <div class="card--featured__body">
        <p>{description}</p>
    </div>
    <div class="card--featured__meta">
        <span>{domain}</span> · <span>r/{subreddit}</span>
    </div>
</a>
```

**Link Card (Reddit):**
```html
<a href="{urls.primary}" class="card card--link content-item">
    <img class="card__favicon" data-size="18" alt="">
    <div class="card__content">
        <span class="card__title">{title}</span>
        <span class="card__desc">{description}</span>
    </div>
</a>
```

**Compact Link Card:**
```html
<a href="{urls.primary}" class="card card--link is-compact content-item">
    <img class="card__favicon" data-size="18" alt="">
    <div class="card__content">
        <span class="card__title">{title}</span>
        <span class="card__desc">{description}</span>
    </div>
</a>
```

**Section Structure:**
```html
<!-- Source Header -->
<div class="source-header content-item">
    <img src="../../WEB/assets/{logo}.svg" alt="{Source}" class="source-header__logo">
    <span class="source-header__label">From {Source}</span>
</div>

<!-- Source Tags -->
<div class="source-tags content-item">
    <a href="https://reddit.com/r/{sub}" class="source-tag">r/{sub}</a>
    <!-- or for PH: -->
    <a href="https://producthunt.com" class="source-tag">Product Hunt</a>
</div>

<!-- Section Intro -->
<p class="section-intro content-item">{editorial_context}</p>

<!-- Cards follow -->
```

### 6.4 Pre-Write URL Checklist

Before writing HTML, mentally verify:
- [ ] Every `href` is a full URL starting with `https://`
- [ ] No generic profile links (e.g., `x.com/username` without `/status/`)
- [ ] All Product Hunt items link to product websites, not PH pages
- [ ] All Reddit items link to primary sources, not Reddit threads

### 6.5 Write PHP File

Write the generated PHP to `digest-archive/{date}/index.php`.

**IMPORTANT**: Copy the PHP preamble from template.php exactly — it handles the feedback form submission.

### 6.6 Post-Write Link Validation

After writing index.php, run the validation script:

1. Run the link validation script:
   ```bash
   ./validate-links.sh digest-archive/{date}/index.php
   ```

2. The script outputs:
   - **BROKEN** (404, 401, etc.) — Must fix
   - **WARNINGS** (403) — Must verify with WebSearch

3. For each **BROKEN** link:
   - Use `WebSearch` to find the correct URL
   - Update the href in index.php

4. For each **403 WARNING** (especially x.com/twitter links):
   - **ALWAYS use WebSearch to verify the URL is correct**
   - X.com returns 403 for bot requests, but ALSO for invalid URLs
   - Search for the content (e.g., "Boris Cherny Claude Code Opus 4.5 twitter")
   - Confirm the URL from search results matches what you have
   - If different, update index.php with the correct URL

5. Re-run validation until:
   - Zero BROKEN links
   - All 403 WARNINGS have been verified via WebSearch

6. Only proceed to completion after all links are validated/verified.

### 6.7 Set File Permissions

After writing files, ensure they are web-readable:

```bash
chmod 644 digest-archive/{date}/index.php digest-archive/{date}/checkpoint.md
```

This sets permissions to `rw-r--r--` (owner read/write, others read-only), allowing the web server to serve the files.

### 6.8 Update Checkpoint

```markdown
phase: complete
html_generated: {timestamp}
items_count: 5
links_validated: true
permissions_set: true
```

---

## Step 7: Update MEMORY.md (if needed)

Each source has a `MEMORY.md` file with a `## Developing Topics` section:
- `### Active` — Ongoing stories to watch for follow-ups
- `### Resolved` — Stories that concluded

**Update MEMORY.md when:**
1. A major story breaks that will likely have follow-ups (add to Active)
2. An Active story reaches conclusion (move to Resolved)
3. You discover context about the user's preferences worth remembering

**Example addition to Active:**
```markdown
- **GPT-5 launch** (added 2025-12-30) — Initial release covered. Watch for: benchmarks, jailbreaks, API pricing, enterprise features.
```

**Skip this step if:** Nothing notable happened — most days won't need MEMORY updates.

---

## Step 8: Send Telegram Notification

After the digest is complete and all links are validated, notify via Telegram.

### 8.1 Send Notification

```bash
curl -s -X POST "https://api.telegram.org/bot8598630114:AAEB6_CcqweCCt4IYyLbnhF_to_qnnbRg4o/sendMessage" \
  -d "chat_id=-5063753582" \
  -d "parse_mode=HTML" \
  -d "text=📝 <b>Daily digest ready</b>%0A%0AYour digest for {Month} {Day}, {Year} is ready. Fresh picks from Product Hunt and Reddit.%0A%0A🔗 https://tonki.dev/digest/digest-archive/{date}/"
```

**Format:**
```
📝 Daily digest ready

Your digest for {Month} {Day}, {Year} is ready. Fresh picks from Product Hunt and Reddit.

🔗 https://tonki.dev/digest/digest-archive/{date}/
```

### 8.2 Update Checkpoint

```markdown
telegram_sent: true
```

---

## Step 9: Signal Completion

**This is the final step.** The orchestrator polls for this signal to know the digest is complete.

### 9.1 Append to Completion Ledger

Append today's ISO date as a new line to `COMPLETED-DAYS.md`:

```bash
echo "{date}" >> COMPLETED-DAYS.md
```

Where `{date}` is in `YYYY-MM-DD` format (e.g., `2025-12-31`).

**Example file after appending:**
```markdown
# Completed Digest Days

2025-12-26
2025-12-27
2025-12-28
2025-12-29
2025-12-30
2025-12-31
```

### 9.2 Update Checkpoint

```markdown
phase: complete
completion_signaled: true
```

**IMPORTANT:**
- This MUST be the absolute last step
- Only append after Telegram notification succeeds
- The orchestrator checks this file to detect completion
- Never append the same date twice (check first if unsure)

---

## Troubleshooting

### If Reddit MCP fails or gets blocked
1. Try switching VPN node: `sg nordvpn -c "nordvpn disconnect" && sg nordvpn -c "nordvpn connect"`
2. Wait 30 seconds, retry
3. If fails 3 times, move to next subreddit
4. Note failure in checkpoint.md

### If context runs out
- Checkpoint.md has all state
- Next execution reads checkpoint, finds last completed step, resumes

### If no interesting posts
- Fine to generate minimal digest
- Note in checkpoint: `no_relevant_content: true`

---

## Resume Protocol

If checkpoint.md exists:

1. Read the file
2. Find `phase:` value and resume:

   | Phase | Resume at | Description |
   |-------|-----------|-------------|
   | `starting` | Step 0.7 | Scan previous digests, then Step 1 |
   | `source-0-complete` | Step 2 | Product Hunt done → AI-LLMs |
   | `source-1-complete` | Step 3 | AI-LLMs done → GenAI-Media |
   | `source-2-complete` | Step 4 | GenAI-Media done → Apps-Software |
   | `source-3-complete` | Step 5 | All sources done → Final Selection |
   | `selection-complete` | Step 6 | Selection done → Generate HTML |
   | `complete` | — | Already done (see below) |

3. **If phase is `complete`:**
   - Check if `telegram_sent: true` exists in checkpoint
   - Check if `completion_signaled: true` exists in checkpoint
   - Check if today's date exists in `COMPLETED-DAYS.md`
   - If ALL are true, your job is done — end the session immediately
   - If Telegram wasn't sent, send it (Step 8)
   - If completion wasn't signaled, do Step 9 (append date to COMPLETED-DAYS.md)
   - If the digest URL fails, check if `index.php` exists and troubleshoot

4. Check for partial progress within a phase:
   - Look for `[x]` vs `[ ]` markers
   - Look for `### Analyzed:` entries
   - Continue from last completed item

5. Do NOT re-fetch already-fetched data
   - Raw data tables persist in checkpoint
   - Only process remaining items

6. **Completion ledger check (COMPLETED-DAYS.md):**
   - If today's date is already in the ledger, the job is truly done
   - The orchestrator uses this file to detect completion
   - Only append the date ONCE after everything succeeds

---

## Final Verification

Before marking complete:
- [ ] All sources were processed (0-3)
- [ ] Checkpoint.md has complete state
- [ ] Every selected item has specific URLs (not generic)
- [ ] index.php was written
- [ ] All links validated (no 404s, all 403s verified via WebSearch)
- [ ] File permissions set to 644 (web-readable)
- [ ] MEMORY.md updated if needed
- [ ] Telegram notification sent
- [ ] Today's date appended to COMPLETED-DAYS.md (Step 9 — completion signal)
