Merge pull request #16 from mohitagw15856/claude/lucid-sagan-YnJQS
Claude/lucid sagan yn jqs
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
|
||||
"name": "pm-claude-skills",
|
||||
"version": "13.0.0",
|
||||
"description": "PM stands for Professional, not just Product Management. 155 Claude Skills + 4 agent templates across 24 bundles covering 17 professions — engineering, customer success, legal, finance, HR, sales, design, Figma, marketing, social media, and more. Built by a PM, used by everyone. Building blocks for the Anthropic agent template architecture.",
|
||||
"version": "14.0.0",
|
||||
"description": "PM stands for Professional, not just Product Management. 167 Claude Skills + 4 agent templates across 26 bundles covering 18 professions — engineering, customer success, legal, finance, HR, sales, design, Figma, marketing, social media, writers, and more. Built by a PM, used by everyone. Building blocks for the Anthropic agent template architecture.",
|
||||
"owner": {
|
||||
"name": "Mohit Aggarwal",
|
||||
"email": "mohit15856@gmail.com"
|
||||
@@ -82,8 +82,8 @@
|
||||
},
|
||||
{
|
||||
"name": "pm-engineering",
|
||||
"description": "Engineering & tech skills: Code Review Checklist, Incident Postmortem, API Docs Writer, Architecture Decision Record, Debugging Log Analyser, PR Description Writer, System Design Interview, Changelog Generator, Test Strategy Doc, Runbook Writer, CI/CD Playbook, SLO & Error Budget, Developer Onboarding Doc, On-Call Runbook, Security Threat Model, Performance Budget, Database Schema Design, Database Migration Plan, Technical Debt Register, RFC Writer, Capacity Planning, Load Testing Plan, Disaster Recovery Plan, Feature Flag Guide, Dependency Audit, Service Catalog Entry, Monitoring Setup Guide, Local Dev Setup, API Versioning Strategy, Infra-as-Code Review, Engineering Weekly Report, Tech Radar, Sprint Velocity Analysis, Microservices Decomposition, Engineering Hiring Rubric. 35 structured skills for engineering teams, SREs, and technical PMs.",
|
||||
"version": "4.0.0",
|
||||
"description": "Engineering & tech skills: Code Review Checklist, Incident Postmortem, API Docs Writer, Architecture Decision Record, Debugging Log Analyser, PR Description Writer, System Design Interview, Changelog Generator, Test Strategy Doc, Runbook Writer, CI/CD Playbook, SLO & Error Budget, Developer Onboarding Doc, On-Call Runbook, Security Threat Model, Performance Budget, Database Schema Design, Database Migration Plan, Technical Debt Register, RFC Writer, Capacity Planning, Load Testing Plan, Disaster Recovery Plan, Feature Flag Guide, Dependency Audit, Service Catalog Entry, Monitoring Setup Guide, Local Dev Setup, API Versioning Strategy, Infra-as-Code Review, Engineering Weekly Report, Tech Radar, Sprint Velocity Analysis, Microservices Decomposition, Engineering Hiring Rubric, Context Mode, Claude Superpowers. 37 structured skills for engineering teams, SREs, technical PMs, and Claude Code power users.",
|
||||
"version": "4.1.0",
|
||||
"category": "productivity",
|
||||
"source": "./plugins/pm-engineering",
|
||||
"homepage": "https://github.com/mohitagw15856/pm-claude-skills"
|
||||
@@ -162,8 +162,8 @@
|
||||
},
|
||||
{
|
||||
"name": "pm-operations",
|
||||
"description": "Operations skills: Process Documentation, SOP Writer, Vendor Evaluation, Project Status Report, Workshop Facilitation Guide, Risk Register, RACI Matrix. Document workflows, write SOPs, build risk registers with L×I scoring, define RACI matrices for cross-functional initiatives, and design facilitated workshops.",
|
||||
"version": "1.2.0",
|
||||
"description": "Operations skills: Process Documentation, SOP Writer, Vendor Evaluation, Project Status Report, Workshop Facilitation Guide, Risk Register, RACI Matrix, Email Triage, Morning Intelligence. Document workflows, write SOPs, build risk registers, define RACI matrices, triage your inbox to only what needs action, and auto-generate a personalised morning news brief.",
|
||||
"version": "1.3.0",
|
||||
"category": "productivity",
|
||||
"source": "./plugins/pm-operations",
|
||||
"homepage": "https://github.com/mohitagw15856/pm-claude-skills"
|
||||
@@ -178,8 +178,8 @@
|
||||
},
|
||||
{
|
||||
"name": "pm-cross",
|
||||
"description": "Cross-profession skills: Press Release, Grant Proposal, Executive Summary, Teaching Lesson Plan. Write journalist-ready press releases, structure grant applications, produce decision-ready executive summaries, and design complete lesson plans for any subject, audience, or setting.",
|
||||
"version": "1.1.0",
|
||||
"description": "Cross-profession skills: Press Release, Grant Proposal, Executive Summary, Teaching Lesson Plan, Sycophancy Challenger, Last 30 Days Research, NotebookLM Connector. Get genuine push-back on your ideas (not validation), gather multi-platform research from the last 30 days, and automate NotebookLM from Claude.",
|
||||
"version": "1.2.0",
|
||||
"category": "productivity",
|
||||
"source": "./plugins/pm-cross",
|
||||
"homepage": "https://github.com/mohitagw15856/pm-claude-skills"
|
||||
@@ -199,6 +199,14 @@
|
||||
"category": "productivity",
|
||||
"source": "./plugins/pm-social",
|
||||
"homepage": "https://github.com/mohitagw15856/pm-claude-skills"
|
||||
},
|
||||
{
|
||||
"name": "pm-writers",
|
||||
"description": "Writers & Content Creators skills: Instagram Post Downloader, AEO Optimizer, Thumbnail Creator, Substack Notes Scraper, Notes Humanizer. Download Instagram carousels as PDFs, restructure articles for AI citation, generate thumbnail candidates via Gemini, export Substack Notes analytics to Excel, and strip AI writing patterns from any text.",
|
||||
"version": "1.0.0",
|
||||
"category": "productivity",
|
||||
"source": "./plugins/pm-writers",
|
||||
"homepage": "https://github.com/mohitagw15856/pm-claude-skills"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
# 🧠 PM Claude Skills — 155 Skills for Every Profession
|
||||
# 🧠 PM Claude Skills — 167 Skills for Every Profession
|
||||
|
||||
[](https://github.com/mohitagw15856/pm-claude-skills/stargazers)
|
||||
[](https://github.com/mohitagw15856/pm-claude-skills)
|
||||
[](https://github.com/mohitagw15856/pm-claude-skills/releases)
|
||||
[](https://github.com/mohitagw15856/pm-claude-skills)
|
||||
[](https://github.com/mohitagw15856/pm-claude-skills/releases)
|
||||
[](https://github.com/mohitagw15856/pm-claude-skills#-quick-install-2-minutes)
|
||||
[](LICENSE)
|
||||
[](https://github.com/sponsors/mohitagw15856)
|
||||
|
||||
> **PM stands for Professional, not just Product Management.**
|
||||
> 155 Claude Skills + 4 agent templates across 24 bundles covering 17 professions. Built by a PM, used by everyone.
|
||||
> 167 Claude Skills + 4 agent templates across 26 bundles covering 18 professions. Built by a PM, used by everyone.
|
||||
|
||||
A community-built library of Claude Skills for professionals across every field — product management, engineering, customer success, marketing, social media, design, legal, finance, HR, sales, operations, research, and more. Each skill is a structured SKILL.md file that teaches Claude how to produce professional-grade outputs for your specific workflows.
|
||||
A community-built library of Claude Skills for professionals across every field — product management, engineering, customer success, marketing, social media, writers, design, legal, finance, HR, sales, operations, research, and more. Each skill is a structured SKILL.md file that teaches Claude how to produce professional-grade outputs for your specific workflows.
|
||||
|
||||
**🆕 Latest release (v13.0.0):** Social Media profession added — 5 new skills for social media managers, content creators, and growth marketers. Audit your social presence, brief influencer partnerships, manage communities at scale, plan paid social campaigns, and build a viral content system.
|
||||
**🆕 Latest release (v14.0.0):** 12 new community-inspired skills across 4 bundles — a brand new Writers & Content Creators profession (Instagram downloader, AEO optimizer, thumbnail creator, Substack scraper, notes humanizer), plus decision-making, productivity, and Claude Code power tools.
|
||||
---
|
||||
|
||||
## 🚀 Quick Install (2 minutes)
|
||||
@@ -51,6 +51,8 @@ claude plugin install pm-figma@pm-claude-skills # Figma
|
||||
|
||||
claude plugin install pm-social@pm-claude-skills # Social Media 🆕
|
||||
|
||||
claude plugin install pm-writers@pm-claude-skills # Writers & Content Creators 🆕
|
||||
|
||||
|
||||
Or clone and symlink for auto-updates:
|
||||
|
||||
@@ -76,7 +78,7 @@ ln -s ~/pm-claude-skills/skills/* ~/.claude/skills/
|
||||
|
||||
On May 5, 2026, Anthropic [released their first agent templates](https://www.anthropic.com/news/finance-agents) — pre-packaged Claude agents that combine **skills, connectors, and subagents** into ready-to-run workflows for financial services.
|
||||
|
||||
This library is the largest open-source collection of professional skills available — covering 16 professions beyond financial services. **The 155 skills here are the building blocks for agent templates outside of finance.**
|
||||
This library is the largest open-source collection of professional skills available — covering 17 professions beyond financial services. **The 167 skills here are the building blocks for agent templates outside of finance.**
|
||||
|
||||
### What is an agent template?
|
||||
|
||||
@@ -153,6 +155,46 @@ More templates will follow. If you want to contribute one, see the [template con
|
||||
|
||||
---
|
||||
|
||||
## 🆕 What's New in v14.0.0 — Writers & Content Creators + 7 Community Skills
|
||||
|
||||
**12 new community-inspired skills across 4 bundles:**
|
||||
|
||||
### New profession: ✍️ Writers & Content Creators (`pm-writers`)
|
||||
|
||||
| Skill | What It Does |
|
||||
|---|---|
|
||||
| **Instagram Post Downloader** 🆕 | Downloads Instagram images and carousels as high-res files; stitches carousel slides into a single PDF |
|
||||
| **AEO Optimizer** 🆕 | Restructures articles for AI citation — rewrites H2s as questions, adds 50–80 word answer capsules, audits paragraph length and trust signals |
|
||||
| **Thumbnail Creator** 🆕 | Generates brand-aligned thumbnail candidates via Gemini API from article copy; Claude evaluates results via computer vision |
|
||||
| **Substack Notes Scraper** 🆕 | Scrapes Substack Notes engagement data (likes, comments, restacks) and exports a formatted .xlsx with filters and conditional formatting |
|
||||
| **Notes Humanizer** 🆕 | Strips AI writing patterns (em dashes, filler phrases, uniform rhythm) and injects genuine human signals — opinion, varied rhythm, specific detail |
|
||||
|
||||
### Extended: `pm-cross` (+3 skills)
|
||||
|
||||
| Skill | What It Does |
|
||||
|---|---|
|
||||
| **Sycophancy Challenger** 🆕 | Flips Claude's default — argues the strongest case *against* your idea first, holds its position under pushback, and only backs down with new evidence |
|
||||
| **Last 30 Days Research** 🆕 | Searches Reddit, X, and the web for the last 30 days on any topic and returns a structured report: consensus, disagreements, pain points, and signal confidence |
|
||||
| **NotebookLM Connector** 🆕 | Automates NotebookLM from Claude Code via Chrome extension — create notebooks, add sources, generate mindmaps and audio overviews |
|
||||
|
||||
### Extended: `pm-operations` (+2 skills)
|
||||
|
||||
| Skill | What It Does |
|
||||
|---|---|
|
||||
| **Email Triage** 🆕 | Reads Gmail for a configurable window, filters out receipts/notifications, and surfaces only what needs a reply or decision — with priority, urgency, and a reply starter |
|
||||
| **Morning Intelligence** 🆕 | 15-question interview that writes a personalised master prompt for your morning news brief, ready to drop into a Cowork Scheduled Task or Claude Code Routine |
|
||||
|
||||
### Extended: `pm-engineering` (+2 skills — for Claude Code users)
|
||||
|
||||
| Skill | What It Does |
|
||||
|---|---|
|
||||
| **Context Mode** 🆕 | Solves Claude Code context bloat and memory loss — filters raw command output and maintains a session log so Claude resumes exactly where it left off after a reset |
|
||||
| **Claude Superpowers** 🆕 | Forces Claude Code to plan before coding, work in isolation, write tests first, and review its own work twice — from 60% first pass to 80%+ |
|
||||
|
||||
The library now includes **167 skills** across **18 professions** + 4 working agent templates.
|
||||
|
||||
---
|
||||
|
||||
## 🆕 What's New in v13.0.0 — Social Media Profession
|
||||
|
||||
**5 new skills — a complete Social Media profession bundle:**
|
||||
@@ -165,7 +207,7 @@ More templates will follow. If you want to contribute one, see the [template con
|
||||
| **Social Ad Campaign** 🆕 | pm-social | Full-funnel paid social campaign plan with audience targeting, ad set architecture, copy for every format (video, static, carousel, lead gen), budget allocation, and A/B testing plan |
|
||||
| **Viral Content Framework** 🆕 | pm-social | Psychology of sharing, 6 proven hook formulas, 5 content structures, platform-specific playbooks for LinkedIn/TikTok/Instagram/X/YouTube, and a repeatable content testing system |
|
||||
|
||||
The library now includes **155 skills** across **17 professions** + 4 working agent templates.
|
||||
The library now includes **167 skills** across **18 professions** + 4 working agent templates.
|
||||
|
||||
Install the new bundle:
|
||||
|
||||
@@ -281,7 +323,7 @@ This repo was built alongside a published article series. Read the full story:
|
||||
|
||||
---
|
||||
|
||||
## 🗂️ All 155 Skills
|
||||
## 🗂️ All 167 Skills
|
||||
|
||||
### 🛠️ Product Management (Skills 1–37)
|
||||
**Bundles:** `pm-essentials` · `pm-discovery` · `pm-planning` · `pm-delivery` · `pm-analytics` · `pm-strategy` · `pm-advanced` · `pm-rituals`
|
||||
@@ -318,7 +360,7 @@ This repo was built alongside a published article series. Read the full story:
|
||||
|
||||
---
|
||||
|
||||
### 👩💻 Engineering & Tech (Skills 46–80)
|
||||
### 👩💻 Engineering & Tech (Skills 46–80, 166–167)
|
||||
**Bundle:** `pm-engineering`
|
||||
|
||||
| # | Skill | Folder | What It Does |
|
||||
@@ -358,6 +400,8 @@ This repo was built alongside a published article series. Read the full story:
|
||||
| 78 | **Sprint Velocity Analysis** 🆕 | `skills/sprint-velocity-analysis/` | Velocity trend analysis, completion rate patterns, blocker frequency, improvement recommendations, and capacity forecast |
|
||||
| 79 | **Microservices Decomposition** 🆕 | `skills/microservices-decomposition/` | Domain-driven service boundary design with bounded context map, communication patterns, data ownership, and strangler fig migration plan |
|
||||
| 80 | **Engineering Hiring Rubric** 🆕 | `skills/engineering-hiring-rubric/` | Technical interview rubric with level expectations, coding scorecard, system design guide, behavioural question bank, and debrief template |
|
||||
| 166 | **Context Mode** 🆕 | `skills/context-mode/` | Filters command output noise and maintains a session log so Claude resumes exactly where it left off after a context reset |
|
||||
| 167 | **Claude Superpowers** 🆕 | `skills/claude-superpowers/` | Forces Claude Code to plan first, work in isolation, write tests before code, and double-review its own output — consistently better first passes |
|
||||
|
||||
---
|
||||
|
||||
@@ -484,7 +528,7 @@ claude plugin install pm-cs@pm-claude-skills
|
||||
|
||||
---
|
||||
|
||||
### ⚙️ Operations (Skills 120–126)
|
||||
### ⚙️ Operations (Skills 120–126, 164–165)
|
||||
**Bundle:** `pm-operations`
|
||||
|
||||
| # | Skill | Folder | What It Does |
|
||||
@@ -496,6 +540,8 @@ claude plugin install pm-cs@pm-claude-skills
|
||||
| 124 | **Workshop Facilitation Guide** | `skills/workshop-facilitation-guide/` | Complete facilitation guides with activity instructions, decision protocols, and facilitator moves |
|
||||
| 125 | **Risk Register** 🆕 | `skills/risk-register/` | L×I risk scoring, RAG heat map, top-risk executive summary, and per-risk mitigation and contingency plans |
|
||||
| 126 | **RACI Matrix** 🆕 | `skills/raci-matrix/` | RACI with role definitions, decision map, anti-pattern guide, and a communication template for all teams |
|
||||
| 164 | **Email Triage** 🆕 | `skills/email-triage/` | Reads Gmail for a configurable window and surfaces only what needs action — priority-ranked with urgency ratings and reply starters |
|
||||
| 165 | **Morning Intelligence** 🆕 | `skills/morning-intelligence/` | 15-question interview that writes a personalised master prompt for your daily news brief, ready for Cowork Scheduled Tasks or Claude Code Routines |
|
||||
|
||||
---
|
||||
|
||||
@@ -513,7 +559,7 @@ claude plugin install pm-cs@pm-claude-skills
|
||||
|
||||
---
|
||||
|
||||
### 🌐 Cross-Profession (Skills 131–134)
|
||||
### 🌐 Cross-Profession (Skills 131–134, 161–163)
|
||||
**Bundle:** `pm-cross`
|
||||
|
||||
| # | Skill | Folder | What It Does |
|
||||
@@ -522,6 +568,9 @@ claude plugin install pm-cs@pm-claude-skills
|
||||
| 132 | **Grant Proposal** | `skills/grant-proposal/` | Complete grant applications aligned to funder priorities with budget narrative |
|
||||
| 133 | **Executive Summary** | `skills/executive-summary/` | Decision-ready executive summaries with bottom line upfront, adapted for any audience |
|
||||
| 134 | **Teaching Lesson Plan** | `skills/teaching-lesson-plan/` | Complete lesson plans for any subject, audience, or setting — with objectives, activities, and formative assessment |
|
||||
| 161 | **Sycophancy Challenger** 🆕 | `skills/sycophancy-challenger/` | Argues the strongest case *against* your idea first — a genuine thinking partner that holds its position under pressure |
|
||||
| 162 | **Last 30 Days Research** 🆕 | `skills/last-30-days-research/` | Searches Reddit, X, and the web for the last 30 days on any topic and returns consensus, disagreements, pain points, and signal confidence |
|
||||
| 163 | **NotebookLM Connector** 🆕 | `skills/notebooklm-connector/` | Automates NotebookLM via Chrome extension — create notebooks, add sources, generate mindmaps and audio overviews from Claude Code |
|
||||
|
||||
---
|
||||
|
||||
@@ -574,9 +623,28 @@ claude plugin install pm-social@pm-claude-skills
|
||||
|
||||
---
|
||||
|
||||
### ✍️ Writers & Content Creators (Skills 156–160)
|
||||
**Bundle:** `pm-writers`
|
||||
|
||||
> Install:
|
||||
|
||||
```
|
||||
claude plugin install pm-writers@pm-claude-skills
|
||||
```
|
||||
|
||||
| # | Skill | Folder | What It Does |
|
||||
|---|---|---|---|
|
||||
| 156 | **Instagram Post Downloader** 🆕 | `skills/instagram-post-downloader/` | Downloads Instagram images and full carousels as high-res files; stitches carousel slides into a single PDF. Requires `*.cdninstagram.com` on domain allowlist |
|
||||
| 157 | **AEO Optimizer** 🆕 | `skills/aeo-optimizer/` | Restructures any article for AI citation — rewrites H2s as questions, adds 50–80 word answer capsules under each, audits paragraph length, and flags trust signals |
|
||||
| 158 | **Thumbnail Creator** 🆕 | `skills/thumbnail-creator/` | Generates brand-aligned thumbnail candidates via Gemini API; Claude evaluates results via computer vision and returns ranked candidates with rationale |
|
||||
| 159 | **Substack Notes Scraper** 🆕 | `skills/substack-notes-scraper/` | Scrapes Substack Notes and exports likes, comments, and restacks to a formatted .xlsx with frozen headers, filters, and top-performer highlighting |
|
||||
| 160 | **Notes Humanizer** 🆕 | `skills/notes-humanizer/` | Strips AI writing patterns (em dashes, filler phrases, uniform rhythm) across 3 phases: audit, strip, inject — returns side-by-side comparison and clean final text |
|
||||
|
||||
---
|
||||
|
||||
## ❤️ Sponsor This Work
|
||||
|
||||
Building and maintaining 155 skills across 24 bundles takes real time — testing skills against new model releases, building new ones from community requests, writing the article series, and keeping documentation current.
|
||||
Building and maintaining 167 skills across 26 bundles takes real time — testing skills against new model releases, building new ones from community requests, writing the article series, and keeping documentation current.
|
||||
|
||||
If these skills save you time at work, consider sponsoring:
|
||||
|
||||
@@ -695,6 +763,8 @@ claude plugin install pm-figma@pm-claude-skills
|
||||
|
||||
claude plugin install pm-social@pm-claude-skills # Social Media 🆕
|
||||
|
||||
claude plugin install pm-writers@pm-claude-skills # Writers & Content Creators 🆕
|
||||
|
||||
---
|
||||
|
||||
## 🤖 Companion Repository — ChatGPT Custom GPTs
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
---
|
||||
name: last-30-days-research
|
||||
description: Multi-platform research skill that gathers recent (last 30 days) opinions, sentiment, and signal on any topic from Reddit, X/Twitter, and the web. Cuts through SEO-stuffed results to surface what real people are actually saying.
|
||||
---
|
||||
|
||||
# Last 30 Days Research
|
||||
|
||||
## The Problem
|
||||
|
||||
Googling gives SEO-stuffed "best of" lists written six months ago by someone who has never used the thing. Real honest takes live on Reddit threads, X replies, and niche communities — but chasing them across platforms eats your afternoon. This skill does the chase for you.
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Required | Notes |
|
||||
|-------|----------|-------|
|
||||
| Topic | Yes | Tool, trend, feature, product, event, company — anything with a name |
|
||||
| Date scope | No | Defaults to last 30 days. Can override to last 7 days or last 90 days |
|
||||
| Angle | No | e.g. "focus on developer sentiment" or "looking for pricing complaints specifically" |
|
||||
|
||||
## Output Structure
|
||||
|
||||
The output is a structured research report with the following sections, delivered in this exact order:
|
||||
|
||||
```
|
||||
## Last 30 Days Research: [Topic]
|
||||
Research window: [Date 30 days ago] → [Today's date]
|
||||
|
||||
---
|
||||
|
||||
## What People Agree On
|
||||
[Consensus points that appear across multiple platforms — most reliable signal]
|
||||
|
||||
## Where People Disagree
|
||||
[Active debates, contrasting views — include which side has more weight]
|
||||
|
||||
## Pain Points That Keep Coming Up
|
||||
[Recurring complaints and frustrations — strongest signal of real problems]
|
||||
|
||||
## Positive Signals
|
||||
[What people genuinely praise — not PR, but unprompted appreciation]
|
||||
|
||||
## Most Interesting Takes
|
||||
[Contrarian, unexpected, or surprisingly insightful comments worth noting]
|
||||
|
||||
## Sources
|
||||
[Links to the most useful threads/posts found — 5–10 links with brief labels]
|
||||
|
||||
## Signal Confidence
|
||||
[High / Medium / Low — with a one-line rationale based on data volume and consistency]
|
||||
```
|
||||
|
||||
Each section should contain substantive content, not placeholders. If a section has no findings (e.g. no positive signals found), state that explicitly rather than leaving it empty or fabricating content.
|
||||
|
||||
## Instructions for Claude
|
||||
|
||||
### Step 1 — Calculate the date window
|
||||
|
||||
Determine today's date and subtract 30 days to get the research start date. Format: YYYY-MM-DD. Use these dates explicitly in every search query.
|
||||
|
||||
### Step 2 — Reddit search
|
||||
|
||||
Run at least three web searches targeting Reddit:
|
||||
|
||||
```
|
||||
site:reddit.com "[topic]" after:[30-days-ago-date]
|
||||
site:reddit.com "[topic]" 2025
|
||||
reddit.com "[topic]" discussion OR thread OR comments
|
||||
```
|
||||
|
||||
For each result: read the thread title, top-level comments, and any highly-upvoted replies. Record the key claims and the URL.
|
||||
|
||||
If the topic has common synonyms or abbreviations, run additional searches with those (e.g. "Claude Code" and "claude.code" and "Anthropic coding tool").
|
||||
|
||||
### Step 3 — X/Twitter search
|
||||
|
||||
Run at least two web searches targeting X:
|
||||
|
||||
```
|
||||
site:twitter.com OR site:x.com "[topic]" after:[30-days-ago-date]
|
||||
"[topic]" site:x.com -is:retweet
|
||||
```
|
||||
|
||||
Note: X search via web has limitations. If results are sparse, supplement with searches for specific accounts known to discuss the topic area (e.g. tech journalists, domain experts).
|
||||
|
||||
### Step 4 — Broader web search
|
||||
|
||||
Run at least two broader searches for articles, blog posts, and commentary:
|
||||
|
||||
```
|
||||
"[topic]" review OR opinion OR experience [month] [year]
|
||||
"[topic]" vs OR alternative OR comparison [month] [year]
|
||||
```
|
||||
|
||||
Target sources: Hacker News, Substack, dev.to, personal blogs, product communities. Avoid press releases and vendor-authored content.
|
||||
|
||||
### Step 5 — Cross-platform corroboration check
|
||||
|
||||
Before writing the report, review everything collected and apply the corroboration rule:
|
||||
|
||||
**When the same point appears on both Reddit and X independently, treat it as strong signal — it's likely true.**
|
||||
|
||||
A point mentioned only once on one platform is a data point, not a finding. Weight your sections accordingly.
|
||||
|
||||
### Step 6 — Write the report
|
||||
|
||||
Populate each section of the output structure. Follow these rules:
|
||||
|
||||
- **What People Agree On**: Only include points you saw on 2+ platforms or in multiple independent threads. These are your most reliable findings.
|
||||
- **Where People Disagree**: Name the sides. "Some say X, others say Y — and the X camp seems louder based on upvote counts / engagement."
|
||||
- **Pain Points**: Be specific. "Performance issues" is weak. "Cold start times over 4 seconds on the free tier" is useful.
|
||||
- **Positive Signals**: Must be unprompted praise, not from product marketing or sponsored content.
|
||||
- **Most Interesting Takes**: At least 2, maximum 5. Quote or closely paraphrase where possible.
|
||||
- **Sources**: Include the actual URLs. Label each one briefly (e.g. "Reddit thread: 'Has anyone switched from X to Y?'").
|
||||
- **Signal Confidence**: Rate High/Medium/Low based on:
|
||||
- High = 10+ sources, consistent signal across platforms
|
||||
- Medium = 5–10 sources, some inconsistency
|
||||
- Low = fewer than 5 sources, or highly fragmented signal
|
||||
|
||||
### Step 7 — Sanity check before delivering
|
||||
|
||||
Before outputting the report, verify:
|
||||
|
||||
- [ ] Every claim in the report traces to an actual source found during research (not prior knowledge)
|
||||
- [ ] The date window was actually applied to searches, not ignored
|
||||
- [ ] No fabricated or hallucinated URLs in the Sources section
|
||||
- [ ] Signal Confidence rating reflects the actual data volume, not optimism
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] At minimum 3 Reddit searches were run with the date filter applied
|
||||
- [ ] At minimum 2 X/Twitter searches were run
|
||||
- [ ] At minimum 2 broader web searches were run
|
||||
- [ ] Cross-platform corroboration principle was applied (same point on multiple platforms = stronger signal)
|
||||
- [ ] Pain Points section contains specific, concrete details — not vague generalisations
|
||||
- [ ] Sources section contains real URLs (not hallucinated), verified during research
|
||||
- [ ] Signal Confidence is rated and justified
|
||||
- [ ] If a section has no findings, it says so explicitly rather than being omitted or padded
|
||||
- [ ] No vendor-authored content or press releases treated as independent signal
|
||||
- [ ] Synonyms and alternative names for the topic were searched
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "What are people saying about Cursor AI from the last 30 days?"
|
||||
- "Research Vercel's recent sentiment"
|
||||
- "Last 30 days on the Arc browser shutdown"
|
||||
- "What's the current vibe on Supabase?"
|
||||
- "What are developers saying about Claude Code lately?"
|
||||
- "Research [topic] from the last 30 days"
|
||||
- "Give me a signal report on [product]"
|
||||
- "What's the Reddit and Twitter take on [trend]?"
|
||||
@@ -0,0 +1,175 @@
|
||||
---
|
||||
name: notebooklm-connector
|
||||
description: Automates NotebookLM from Claude Code — creates notebooks, adds sources, and triggers outputs (mindmaps, audio overviews, slide decks) without manual clicking via the Claude Chrome extension.
|
||||
---
|
||||
|
||||
# NotebookLM Connector
|
||||
|
||||
## The Problem
|
||||
|
||||
NotebookLM is one of the best AI research tools — but it doesn't connect to your other tools. Every notebook requires manual setup inside the NotebookLM UI: open browser, name the notebook, paste URLs one by one, click generate. For researchers, builders, or anyone who works with a high volume of sources, this friction compounds fast.
|
||||
|
||||
This skill automates NotebookLM from Claude Code using browser automation via the Claude Chrome extension.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
| Requirement | Details |
|
||||
|-------------|---------|
|
||||
| Claude Chrome extension | Must be installed and active in your Chrome browser |
|
||||
| NotebookLM account | Active account at notebooklm.google.com |
|
||||
| Chrome browser | Open and signed into NotebookLM |
|
||||
|
||||
If the Chrome extension is not installed, this skill cannot function. There is no fallback — you will need to perform actions manually.
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Required | Notes |
|
||||
|-------|----------|-------|
|
||||
| Action(s) to perform | Yes | What you want done — see Supported Actions below |
|
||||
| Notebook name | Conditional | Required for create; optional for add/generate if a notebook is already open |
|
||||
| Sources | Conditional | Required for add sources action — URLs, file paths, or pasted text |
|
||||
| Output type | Conditional | Required for generate action — mindmap, audio overview, or briefing doc |
|
||||
|
||||
## Supported Actions
|
||||
|
||||
| Action | What It Does |
|
||||
|--------|-------------|
|
||||
| Create notebook | Opens NotebookLM, creates a new notebook with the specified title |
|
||||
| Add sources | Adds one or more URLs, files, or text blocks as sources to a notebook |
|
||||
| Generate mindmap | Triggers mindmap generation from the notebook's sources |
|
||||
| Generate audio overview | Requests an audio overview (note: takes several minutes to render) |
|
||||
| Generate briefing doc | Requests a briefing document or slide deck from sources |
|
||||
| List notebooks | Lists your existing notebooks and their source counts |
|
||||
| Open notebook | Navigates to a specific existing notebook by name |
|
||||
|
||||
Actions can be chained in a single request: "Create a notebook called 'AI Trends Q2', add these 3 URLs as sources, then generate a mindmap."
|
||||
|
||||
## Output Structure
|
||||
|
||||
After completing actions, Claude returns a structured confirmation:
|
||||
|
||||
```
|
||||
## NotebookLM — Actions Completed
|
||||
|
||||
**Notebook:** [Notebook name]
|
||||
**URL:** [Direct link to the notebook]
|
||||
**Actions completed:**
|
||||
- [x] Created notebook: "[Name]"
|
||||
- [x] Added source: [URL or file name]
|
||||
- [x] Added source: [URL or file name]
|
||||
- [x] Triggered: Mindmap generation
|
||||
|
||||
**Status:** [Any pending items — e.g. "Audio overview is generating, check back in 5–10 minutes"]
|
||||
|
||||
**Notes:** [Any issues encountered or deviations from the requested actions]
|
||||
```
|
||||
|
||||
If an action fails, the failed step is marked with `[ ]` and a reason is provided. See Error Handling below.
|
||||
|
||||
## Instructions for Claude
|
||||
|
||||
### Step 1 — Parse and confirm the request
|
||||
|
||||
Before opening any browser, parse the full request into discrete steps:
|
||||
|
||||
1. What notebook is being targeted (new or existing)?
|
||||
2. What sources need to be added (list each URL or file)?
|
||||
3. What outputs need to be generated?
|
||||
|
||||
If anything is ambiguous — e.g. "add my research sources" without specifying what they are — ask for clarification before proceeding. Do not guess at source URLs.
|
||||
|
||||
### Step 2 — Check the Chrome extension is available
|
||||
|
||||
Confirm browser automation is available via the Claude Chrome extension. If it is not active, stop and report:
|
||||
|
||||
> "This skill requires the Claude Chrome extension to be installed and active. Please install it at [extension URL] and try again."
|
||||
|
||||
### Step 3 — Navigate to NotebookLM
|
||||
|
||||
Open or navigate to `https://notebooklm.google.com`. Confirm the user is logged in. If a login screen appears, stop and ask the user to log in manually, then retry.
|
||||
|
||||
### Step 4 — Execute actions in order
|
||||
|
||||
Execute each action in the sequence requested. After each action, confirm it completed before moving to the next. Do not batch actions speculatively.
|
||||
|
||||
**Creating a notebook:**
|
||||
- Click "New Notebook"
|
||||
- Enter the specified title
|
||||
- Confirm the notebook is created and visible
|
||||
|
||||
**Adding a URL source:**
|
||||
- In the notebook, click "Add Source"
|
||||
- Select "Website" or "URL"
|
||||
- Paste the URL
|
||||
- Wait for the source to process and appear in the sources list
|
||||
- Confirm before adding the next source
|
||||
|
||||
**Adding pasted text:**
|
||||
- Click "Add Source"
|
||||
- Select "Copied text" or "Paste text"
|
||||
- Paste the content
|
||||
- Confirm the source appears
|
||||
|
||||
**Generating a mindmap:**
|
||||
- Navigate to the notebook's output options
|
||||
- Select "Mindmap" from available outputs
|
||||
- Trigger generation
|
||||
- Confirm the mindmap begins rendering
|
||||
|
||||
**Generating an audio overview:**
|
||||
- Navigate to output options
|
||||
- Select "Audio Overview"
|
||||
- Trigger generation
|
||||
- Note: rendering takes several minutes — report this to the user, do not wait for completion
|
||||
|
||||
### Step 5 — Compile and return the confirmation
|
||||
|
||||
Return the structured output described in the Output Structure section above, including the direct notebook URL and a checklist of completed/failed actions.
|
||||
|
||||
## Error Handling
|
||||
|
||||
If any step fails, do the following:
|
||||
|
||||
1. Stop at the failed step (do not attempt to continue)
|
||||
2. Report the exact step that failed and what was observed
|
||||
3. Suggest a manual workaround for that step
|
||||
4. Offer to retry from that point
|
||||
|
||||
**Common failures and workarounds:**
|
||||
|
||||
| Failure | Likely Cause | Manual Workaround |
|
||||
|---------|-------------|-------------------|
|
||||
| Extension not detected | Extension not installed or disabled | Install from Chrome Web Store |
|
||||
| Login screen appears | Session expired | Log in manually, then retry |
|
||||
| Source fails to process | URL is paywalled or blocked | Download content and add as pasted text instead |
|
||||
| Mindmap not available | Source volume too low | Add more sources (NotebookLM requires minimum content) |
|
||||
| Audio overview grayed out | Sources not yet indexed | Wait 1–2 minutes for indexing, then retry |
|
||||
|
||||
## Limitations
|
||||
|
||||
- **Chrome extension required** — This skill does not work in the Claude web interface without the extension. It cannot function in API-only or terminal-only Claude setups.
|
||||
- **NotebookLM UI changes** — If Google updates the NotebookLM interface, specific steps (button names, navigation paths) may need to be updated in this skill.
|
||||
- **Audio overview render time** — Audio overviews are queued server-side by NotebookLM and typically take 5–15 minutes. Claude can trigger the request but cannot wait for completion.
|
||||
- **File uploads** — Uploading local files (PDFs, docs) requires the file to be accessible from the browser. File paths must be absolute.
|
||||
- **Session state** — Claude cannot save or restore NotebookLM session state between conversations. Each session starts fresh.
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] User's full request was parsed into discrete steps before any browser action was taken
|
||||
- [ ] Ambiguous source references were clarified before proceeding
|
||||
- [ ] Each action was confirmed complete before the next one started
|
||||
- [ ] Direct notebook URL is included in the output
|
||||
- [ ] If audio overview was triggered, user was informed of the render delay
|
||||
- [ ] Any failed steps are explicitly reported with the specific failure reason
|
||||
- [ ] Manual workaround was offered for any step that failed
|
||||
- [ ] Output checklist accurately reflects what was completed vs. what failed
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "Open NotebookLM and create a notebook called 'Competitor Analysis Q2'"
|
||||
- "Add these 5 URLs as sources to my NotebookLM notebook"
|
||||
- "Generate a mindmap in NotebookLM from my current notebook"
|
||||
- "Create a NotebookLM notebook on AI agent frameworks, add these sources, and generate an audio overview"
|
||||
- "What notebooks do I have in NotebookLM?"
|
||||
- "Add this article to NotebookLM: [URL]"
|
||||
- "Generate a briefing doc from my NotebookLM sources on [topic]"
|
||||
@@ -0,0 +1,156 @@
|
||||
---
|
||||
name: sycophancy-challenger
|
||||
description: Flips Claude's default from "find reasons you're right" to "find reasons you're wrong." A genuine thinking partner, not a mirror with grammar. Use before high-stakes decisions, plans, assumptions, or pitches you haven't stress-tested.
|
||||
---
|
||||
|
||||
# Sycophancy Challenger
|
||||
|
||||
Claude defaults to validating. You bring a decision, it finds three reasons your instinct is solid, and you leave more confident but not more right. That's actively dangerous when the stakes are high — a hiring call, a pricing change, a strategy pivot, a public commitment. This skill flips the default: Claude argues against your idea first, holds its position under pushback, and only concedes when you give it new evidence. Not when you express displeasure.
|
||||
|
||||
> Credit: Originally created by Joel Salinas (Leadership in Change) — adapted and extended for this library.
|
||||
|
||||
---
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Format | Notes |
|
||||
|---|---|---|
|
||||
| Your idea, decision, plan, or assumption | Describe it in plain language | More context = sharper challenge. Include reasoning if you have it. |
|
||||
|
||||
No other setup required. Activating the skill is enough — describe your idea and Claude will challenge it immediately.
|
||||
|
||||
---
|
||||
|
||||
## Output Structure
|
||||
|
||||
Every response in this mode follows this exact format:
|
||||
|
||||
```
|
||||
## Strongest Case AGAINST This
|
||||
|
||||
[The single most damaging criticism of the idea. Not a list of concerns — the
|
||||
one argument that, if true, would kill this. Stated directly, without softening.]
|
||||
|
||||
|
||||
## The Weakest Element
|
||||
|
||||
[The specific part of the idea most likely to fail, be wrong, or break under
|
||||
real-world conditions. Named precisely. Not "execution risk" — the actual thing.]
|
||||
|
||||
|
||||
## What You'd Need to Prove to Make This Work
|
||||
|
||||
[The assumptions that must be true for this idea to succeed. Written as testable
|
||||
claims, not as encouragement. If an assumption can't be tested, that's noted.]
|
||||
|
||||
|
||||
## What I Can't Find Fault With
|
||||
|
||||
[Only appears when a genuine search finds nothing damaging. States clearly what
|
||||
holds up and why — doesn't invent weak praise to fill the section. If everything
|
||||
is actually fine, says so plainly and explains why the challenge came up short.]
|
||||
```
|
||||
|
||||
No additional sections. No summary. No "overall, this is a solid idea." The format ends when the four sections are complete.
|
||||
|
||||
---
|
||||
|
||||
## Instructions for Claude
|
||||
|
||||
### On activation
|
||||
|
||||
Do not open with agreement, validation, or any form of "I see where you're coming from." Begin the challenge immediately. The first word of your response should advance the criticism, not soften the user's expectations.
|
||||
|
||||
### Step 1: Assume the idea hasn't been stress-tested
|
||||
|
||||
Treat the idea as if the user believes in it strongly and has not actively looked for reasons it fails. Your job is to be the adversary they didn't have in the room.
|
||||
|
||||
### Step 2: Find the strongest case against it
|
||||
|
||||
Not a balanced view. Not pros and cons. The strongest case against. Ask:
|
||||
- What's the most likely way this fails?
|
||||
- What's the assumption that, if wrong, makes everything else irrelevant?
|
||||
- Who would argue against this, and what's the best version of their argument?
|
||||
- What does this idea get wrong about how people, markets, or systems actually behave?
|
||||
|
||||
State the strongest case directly. Do not list multiple criticisms in this section — lead with the one that does the most damage.
|
||||
|
||||
### Step 3: Identify the weakest element
|
||||
|
||||
This is different from the strongest case against. The weakest element is the most fragile specific component — the thing most likely to crack under execution, scrutiny, or changed conditions. Name it precisely. Examples of insufficient answers:
|
||||
- "The timeline might be tight" → insufficient
|
||||
- "The assumption that customers will pay $99/month before experiencing the product is the element most likely to break this, because you have no evidence of willingness-to-pay at that price point" → correct level of specificity
|
||||
|
||||
### Step 4: Surface the required assumptions
|
||||
|
||||
List what must be true for this to work. Write each assumption as a testable claim:
|
||||
|
||||
```
|
||||
For this to work, the following must be true:
|
||||
1. [Assumption stated as a claim that can be verified or falsified]
|
||||
2. [Assumption stated as a claim]
|
||||
3. [Assumption stated as a claim]
|
||||
```
|
||||
|
||||
If an assumption cannot be tested — it's based on hope, belief, or unprovable prediction — flag it explicitly: "This assumption cannot currently be tested. That's a risk."
|
||||
|
||||
### Step 5: Report what holds up (only if true)
|
||||
|
||||
Search genuinely for what the idea gets right or where the challenge fails. If you find it, state it clearly. If you can't find a real flaw, say exactly that: "I've looked for the failure points and I can't find them. Here's what actually holds up: [specific things]." Do not invent praise. Do not invent flaws either.
|
||||
|
||||
### Handling pushback
|
||||
|
||||
If the user pushes back:
|
||||
- **New evidence or new information:** update your position based on the evidence. State what changed and why.
|
||||
- **Emotional pushback, repetition, or displeasure:** do not move. Restate the criticism calmly. Example: "I understand you feel strongly about this — I'm not backing off the point about X because that hasn't changed. If there's something I'm missing, tell me what it is."
|
||||
- **A clarification that changes the picture:** acknowledge the clarification, adjust if warranted, and explain exactly what the clarification changed.
|
||||
|
||||
Do not soften a position because the user seems upset. Do not move back to validation mode mid-conversation.
|
||||
|
||||
### When the skill ends
|
||||
|
||||
The session is complete when the user has either:
|
||||
1. Strengthened their idea by addressing the core criticism with real evidence or a genuine plan adjustment, or
|
||||
2. Identified a real flaw they're going to fix.
|
||||
|
||||
Not when they've expressed satisfaction. Not when a certain number of exchanges have happened. The measure is whether something actually changed or was genuinely defended.
|
||||
|
||||
### Prohibitions
|
||||
|
||||
These prohibitions do more work than the rules above. Follow them absolutely:
|
||||
|
||||
- **Never open with agreement or validation.** Not "That's an interesting approach," not "I can see why you'd think that." Start with the challenge.
|
||||
- **Never say "great question," "great point," or "I see where you're coming from" as a lead.** These are validation openers, not neutral transitions.
|
||||
- **Never soften a criticism with "however, there are also positives."** If the positives are real, they go in the "What I Can't Find Fault With" section, not as a counterweight to every criticism.
|
||||
- **Never back down because the user expressed displeasure.** Only move if given new evidence.
|
||||
- **Never invent a flaw that isn't real.** If the idea is actually solid, say so. Inventing fake criticisms is as useless as fake validation.
|
||||
- **Never use the word "valid" to describe the user's perspective mid-challenge.** It's a validation signal disguised as a neutral word.
|
||||
|
||||
---
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] Response opened with the challenge — not with a softening phrase or acknowledgment
|
||||
- [ ] "Strongest Case Against" section contains one argument, not a list
|
||||
- [ ] "Weakest Element" is specific — names the actual component, not a category of risk
|
||||
- [ ] "What You'd Need to Prove" lists testable assumptions, not encouragement
|
||||
- [ ] Untestable assumptions are explicitly flagged as risks
|
||||
- [ ] "What I Can't Find Fault With" only appears if the search was genuine and something held up
|
||||
- [ ] No invented flaws — every criticism connects to something real in what the user described
|
||||
- [ ] Pushback was met with a position restatement, not a retreat (unless new evidence was provided)
|
||||
- [ ] The session ended because something changed or was genuinely defended — not because the user seemed satisfied
|
||||
- [ ] None of the prohibited phrases or patterns appear anywhere in the response
|
||||
|
||||
---
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "Use the sycophancy-challenger skill — here's my plan: [describe it]"
|
||||
- "Challenge this idea before I commit to it: [describe it]"
|
||||
- "I've already decided to do X — tell me why I'm wrong"
|
||||
- "Be the devil's advocate on this hire: [describe the candidate and the role]"
|
||||
- "I'm about to pitch this to investors — tear it apart first: [describe it]"
|
||||
- "Don't validate this, challenge it: [idea or assumption]"
|
||||
- "Stress-test this strategy: [describe it]"
|
||||
- "What's the strongest argument against doing this: [decision]"
|
||||
- "I think I'm right about X — what am I missing?"
|
||||
@@ -0,0 +1,282 @@
|
||||
---
|
||||
name: claude-superpowers
|
||||
description: "Force Claude Code to work like a senior developer: plan before coding, work in isolation, write tests first, and review its own output twice before presenting it. Use when asked to enable superpowers mode, activate the superpowers framework, or turn on superpowers for this session. Installs a 4-stage framework — Plan, Isolate, Test First, Double Review — that prevents Claude from sprinting into broken code."
|
||||
---
|
||||
|
||||
# Claude Superpowers Skill
|
||||
|
||||
Stop Claude from shipping the first thing it writes. Superpowers mode locks Claude into four stages — Plan, Isolate, Test First, Double Review — so that what it presents at the end is actually right.
|
||||
|
||||
The default problem: Claude sprints out of the gate, writes the whole thing in one shot, and it looks great — until someone runs it. It doesn't plan. It doesn't test. It doesn't verify. The result: code that breaks on edge cases, debugging rounds that burn tokens, and rework that costs more than doing it right the first time.
|
||||
|
||||
> **Credit:** Inspired by a skill from Nate Herk's YouTube channel — adapted and extended for this library.
|
||||
|
||||
---
|
||||
|
||||
## Required Inputs
|
||||
|
||||
No inputs required. Superpowers activates on command, then applies to whatever coding task follows.
|
||||
|
||||
---
|
||||
|
||||
## The Four Stages
|
||||
|
||||
### Stage 1 — Plan
|
||||
|
||||
Before writing a single line of code, Claude must produce a written plan and wait for user confirmation.
|
||||
|
||||
**Plan format:**
|
||||
|
||||
```
|
||||
PLAN
|
||||
════
|
||||
|
||||
TASK
|
||||
[One-sentence restatement of what was asked. If anything is ambiguous, flag it here before proceeding.]
|
||||
|
||||
APPROACH
|
||||
[2–4 sentences describing the implementation approach and key decisions. If there are multiple valid approaches, briefly explain why this one was chosen.]
|
||||
|
||||
FILES TO CREATE OR MODIFY
|
||||
- [path/to/file.ts] — [what changes: create / modify / delete — one line reason]
|
||||
- [path/to/file.ts] — [what changes]
|
||||
|
||||
EDGE CASES I WILL HANDLE
|
||||
- [Edge case 1]
|
||||
- [Edge case 2]
|
||||
- [Edge case 3]
|
||||
|
||||
EDGE CASES I AM NOT HANDLING (out of scope)
|
||||
- [Out of scope case — reason]
|
||||
|
||||
ASSUMPTIONS
|
||||
- [Any assumption made where the requirements were unclear]
|
||||
|
||||
Confirm this plan before I start coding.
|
||||
```
|
||||
|
||||
Claude must not proceed until the user says yes (or provides corrections). If the user corrects the plan, revise and re-confirm before starting.
|
||||
|
||||
---
|
||||
|
||||
### Stage 2 — Isolate
|
||||
|
||||
Claude works in isolation until the output is complete and reviewed. Nothing touches the main project until explicitly approved.
|
||||
|
||||
**Isolation rules:**
|
||||
- If git is available: create a feature branch before making any changes. Branch name format: `superpowers/[task-slug]`
|
||||
- If no git: note that changes are being made to a working copy and flag all modified files at the end for user review before they're considered "shipped"
|
||||
- Do not modify files outside the scope defined in the plan unless the user explicitly expands scope during the session
|
||||
- If new scope is discovered mid-task (e.g. a dependency needs to change), surface it: "This requires also modifying [X] — should I include that in scope?"
|
||||
|
||||
**On starting Stage 2, announce:**
|
||||
```
|
||||
ISOLATE
|
||||
Working in isolation on branch: superpowers/[task-slug]
|
||||
No changes will be considered final until Stage 4 review is complete.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Stage 3 — Test First
|
||||
|
||||
Before writing the implementation, write the tests (or at minimum, define the expected behaviour as executable assertions).
|
||||
|
||||
**Test-first approach:**
|
||||
1. Write tests that define the expected behaviour for the task
|
||||
2. Write tests that cover each edge case identified in the plan
|
||||
3. Run the tests — they should fail (implementation doesn't exist yet)
|
||||
4. Confirm the tests are failing for the right reason before writing implementation
|
||||
5. Write the implementation
|
||||
6. Run the tests — they should now pass
|
||||
7. If tests fail: fix the implementation, not the tests
|
||||
|
||||
**If the project has no test setup:** flag it and offer two options:
|
||||
- Option A: Set up a minimal test harness before proceeding (recommended)
|
||||
- Option B: Define the expected behaviour as a checklist of manual verification steps (faster but weaker)
|
||||
|
||||
**Test summary to show before writing implementation:**
|
||||
|
||||
```
|
||||
TESTS WRITTEN
|
||||
─────────────
|
||||
File: [test file path]
|
||||
Tests:
|
||||
✗ [test description — covers: happy path]
|
||||
✗ [test description — covers: edge case 1]
|
||||
✗ [test description — covers: edge case 2]
|
||||
✗ [test description — covers: error state]
|
||||
|
||||
All tests failing as expected. Starting implementation.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Stage 4 — Double Review
|
||||
|
||||
After completing the code and running tests, Claude reviews its own work twice before presenting it. Neither review is a formality.
|
||||
|
||||
**Review 1 — "Does this match what was asked for?"**
|
||||
|
||||
Check the completed code against the original request and confirmed plan:
|
||||
- Does it do everything that was asked?
|
||||
- Does it handle all edge cases from the plan?
|
||||
- Are there any mismatches between what was planned and what was built?
|
||||
- Are there any assumptions baked in that weren't confirmed?
|
||||
|
||||
**Review 2 — "Is this good code?"**
|
||||
|
||||
Check for technical quality independent of the requirements:
|
||||
- Obvious bugs or logic errors
|
||||
- Missing error handling (especially at boundaries: API calls, file I/O, user input)
|
||||
- Security issues (injection vulnerabilities, exposed secrets, missing auth checks)
|
||||
- Readability: would another developer understand this in 6 months?
|
||||
- Performance: any obvious inefficiencies on the critical path?
|
||||
- Dead code or unused imports introduced
|
||||
|
||||
**Double Review output format:**
|
||||
|
||||
```
|
||||
REVIEW 1 — CORRECTNESS
|
||||
───────────────────────
|
||||
✅ Handles [requirement 1]
|
||||
✅ Handles [requirement 2]
|
||||
✅ Edge case [X] covered
|
||||
⚠️ [Issue found — what it is and what was changed to fix it]
|
||||
|
||||
REVIEW 2 — CODE QUALITY
|
||||
────────────────────────
|
||||
✅ Error handling present at all API boundaries
|
||||
✅ No obvious security issues
|
||||
⚠️ [Issue found — what it was and how it was fixed]
|
||||
✅ Readable — no unexplained complexity
|
||||
|
||||
VERDICT: [Ready to present / Fixed N issues before presenting]
|
||||
```
|
||||
|
||||
If issues are found in either review, fix them and note what was fixed. Present the corrected version, not the original draft.
|
||||
|
||||
---
|
||||
|
||||
## Activation Response
|
||||
|
||||
When the user triggers Superpowers mode, respond with:
|
||||
|
||||
```
|
||||
Superpowers mode active.
|
||||
|
||||
I'll work in 4 stages for every coding task this session:
|
||||
1. PLAN — Write a plan and wait for your confirmation before coding
|
||||
2. ISOLATE — Work on a branch; nothing ships until you approve
|
||||
3. TEST — Write tests before the implementation
|
||||
4. REVIEW — Review my own work twice before presenting it
|
||||
|
||||
What are we building?
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Output Structure
|
||||
|
||||
### Full task flow (all four stages)
|
||||
|
||||
```
|
||||
PLAN
|
||||
════
|
||||
[Plan format as above]
|
||||
Confirm this plan before I start coding.
|
||||
|
||||
---
|
||||
[User confirms]
|
||||
---
|
||||
|
||||
ISOLATE
|
||||
Working in isolation on branch: superpowers/[task-slug]
|
||||
|
||||
TESTS WRITTEN
|
||||
─────────────
|
||||
[Test summary — all failing]
|
||||
Starting implementation.
|
||||
|
||||
---
|
||||
[Implementation runs]
|
||||
---
|
||||
|
||||
REVIEW 1 — CORRECTNESS
|
||||
───────────────────────
|
||||
[Checklist]
|
||||
|
||||
REVIEW 2 — CODE QUALITY
|
||||
────────────────────────
|
||||
[Checklist]
|
||||
|
||||
VERDICT: Ready to present.
|
||||
|
||||
---
|
||||
|
||||
COMPLETE
|
||||
════════
|
||||
[Summary of what was built, files created/modified, how to run/test it]
|
||||
Branch: superpowers/[task-slug] — merge when ready.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CLAUDE.md Installation Text
|
||||
|
||||
After activating Superpowers for the session, provide the user with the exact text to add to their `CLAUDE.md` to make it permanent:
|
||||
|
||||
````
|
||||
```
|
||||
## Superpowers Framework
|
||||
|
||||
This framework is always active for coding tasks in this project.
|
||||
|
||||
### Stage 1 — Plan
|
||||
Before writing any code: produce a written plan including task restatement, approach, files to create/modify, edge cases to handle, and assumptions. Wait for explicit user confirmation before proceeding.
|
||||
|
||||
### Stage 2 — Isolate
|
||||
Work on a feature branch (superpowers/[task-slug]) or clearly flagged working copy. Nothing is considered shipped until the user approves after Stage 4.
|
||||
|
||||
### Stage 3 — Test First
|
||||
Write tests before writing the implementation. Tests should fail before implementation, pass after. If no test setup exists, offer to create one or produce a manual verification checklist.
|
||||
|
||||
### Stage 4 — Double Review
|
||||
After completing code, run two reviews before presenting:
|
||||
- Review 1: Does this match what was asked for? Check against original request and plan.
|
||||
- Review 2: Is this good code? Check for bugs, missing error handling, security issues, readability.
|
||||
Fix any issues found. Present the corrected version. Show the review checklist.
|
||||
```
|
||||
````
|
||||
|
||||
Tell the user: "Add this to your CLAUDE.md and Superpowers will be active permanently for this project."
|
||||
|
||||
---
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] Stage 1 plan was shown and user explicitly confirmed before any code was written
|
||||
- [ ] Plan includes: task restatement, approach, files to modify, edge cases in scope, edge cases out of scope, assumptions
|
||||
- [ ] Ambiguities in the original request were flagged in the plan (not silently assumed)
|
||||
- [ ] Stage 2 isolation: a feature branch was created (or flagged as working copy if no git)
|
||||
- [ ] Stage 3 tests were written before implementation — not after
|
||||
- [ ] Tests were run and confirmed to be failing before implementation started
|
||||
- [ ] Stage 4 Review 1 checked against the original request — not just against the plan
|
||||
- [ ] Stage 4 Review 2 checked for bugs, error handling, security, readability — all four
|
||||
- [ ] Issues found in either review were fixed before presenting — not flagged as "things to fix later"
|
||||
- [ ] Final output shows what was built, which files were changed, and how to run/test it
|
||||
- [ ] CLAUDE.md installation text was offered after activation
|
||||
|
||||
---
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "Enable superpowers mode"
|
||||
- "Activate superpowers"
|
||||
- "Turn on superpowers for this session"
|
||||
- "Use the superpowers framework"
|
||||
- "Make sure you plan before coding"
|
||||
- "I want you to review your work before showing me"
|
||||
- "Write tests first this time"
|
||||
- "Slow down and plan it out before you start building"
|
||||
- "Work on a branch and show me a plan before touching anything"
|
||||
@@ -0,0 +1,248 @@
|
||||
---
|
||||
name: context-mode
|
||||
description: "Activate output filtering, session logging, and auto-resume to keep Claude Code sessions running for hours without context bloat or memory loss. Use when asked to enable context mode, turn on long session mode, or activate session persistence. Installs a session log at project root, filters verbose command output before it enters context, and auto-resumes after Claude resets."
|
||||
---
|
||||
|
||||
# Context Mode Skill
|
||||
|
||||
Fix the two session killers that end most Claude Code sessions in under 30 minutes: context bloat from raw command output, and memory loss after a reset.
|
||||
|
||||
Context Mode runs three systems simultaneously to keep sessions alive:
|
||||
|
||||
- **Output Filtering** — strips verbose command output before it enters context
|
||||
- **Session Log** — writes a running log of everything that happened
|
||||
- **Auto-Resume** — reads the log on reset and picks up exactly where you left off
|
||||
|
||||
> **Credit:** Inspired by a skill from Nate Herk's YouTube channel — adapted and extended for this library.
|
||||
|
||||
---
|
||||
|
||||
## Required Inputs
|
||||
|
||||
No inputs required. Context Mode activates on command.
|
||||
|
||||
Optional: user can specify a custom log file path if they don't want `session.log` in the project root.
|
||||
|
||||
---
|
||||
|
||||
## How Context Mode Works
|
||||
|
||||
### Part 1 — Output Filtering
|
||||
|
||||
The problem: every time Claude Code runs a command, the full raw output enters the context window. A single `npm install` can dump hundreds of lines. A test suite run? Thousands. Within 30 minutes, the context is full of noise and Claude resets.
|
||||
|
||||
The fix: before any command output enters context, filter it to the useful summary only.
|
||||
|
||||
**What gets kept:**
|
||||
- Last 10 lines of stdout
|
||||
- Every line containing `error`, `warn`, `fail`, `exception`, `traceback`, or `fatal` (case-insensitive)
|
||||
- The exit code
|
||||
- A one-line summary of what the command did and whether it succeeded
|
||||
|
||||
**What gets discarded:**
|
||||
- Middle section of long stdout (replaced with `[... N lines of output truncated ...]`)
|
||||
- Progress bars, download indicators, verbose install logs
|
||||
- Repeated identical lines (deduplicated)
|
||||
|
||||
**Filtering summary format:**
|
||||
|
||||
```
|
||||
COMMAND: [command run]
|
||||
STATUS: [exit code — success / failed]
|
||||
SUMMARY: [one sentence: what happened]
|
||||
ERRORS: [any error/warn lines — or "none"]
|
||||
TAIL: [last 10 lines of stdout]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Part 2 — Session Log
|
||||
|
||||
Claude maintains a running log file at `[project root]/session.log`. This file is written after every significant action and is the source of truth for resuming after a reset.
|
||||
|
||||
**Session log format:**
|
||||
|
||||
```
|
||||
SESSION LOG
|
||||
===========
|
||||
Started: [timestamp]
|
||||
Branch: [current git branch]
|
||||
Directory: [working directory]
|
||||
|
||||
FILES EDITED
|
||||
────────────
|
||||
[timestamp] [file path] — [one-line description of what changed]
|
||||
|
||||
COMMANDS RUN
|
||||
────────────
|
||||
[timestamp] [command] — [outcome: success / failed — brief reason]
|
||||
|
||||
TASKS IN PROGRESS
|
||||
─────────────────
|
||||
[ ] [Task description — what's been done so far and what's left]
|
||||
[x] [Completed task]
|
||||
|
||||
LAST USER PROMPT
|
||||
────────────────
|
||||
[The most recent instruction from the user, verbatim]
|
||||
|
||||
LAST ACTION TAKEN
|
||||
─────────────────
|
||||
[What Claude did last, in one sentence]
|
||||
```
|
||||
|
||||
**Log update rules:**
|
||||
- Write to `session.log` after every file edit
|
||||
- Write to `session.log` after every command run
|
||||
- Update "Tasks in Progress" when a task is started, progressed, or completed
|
||||
- Always overwrite "Last User Prompt" and "Last Action Taken" with the current values — don't append, replace
|
||||
|
||||
---
|
||||
|
||||
### Part 3 — Resume on Reset
|
||||
|
||||
When a new Claude session starts, the first action is:
|
||||
|
||||
1. Check for `session.log` in the project root
|
||||
2. If found, read it and announce the resume:
|
||||
|
||||
```
|
||||
Resuming session.
|
||||
|
||||
Branch: [branch]
|
||||
Last working on: [last task in progress]
|
||||
Files edited: [list from session log]
|
||||
Tasks pending: [incomplete tasks]
|
||||
Last prompt: "[last user prompt]"
|
||||
|
||||
Continuing from where we left off.
|
||||
```
|
||||
|
||||
3. Continue with the next logical step — don't ask "what should I do?" — check the task list and carry on
|
||||
|
||||
If no `session.log` exists, start fresh and initialise the log.
|
||||
|
||||
---
|
||||
|
||||
## Activation Response
|
||||
|
||||
When the user triggers Context Mode, respond with:
|
||||
|
||||
```
|
||||
Context Mode active.
|
||||
|
||||
Session log initialised at: [absolute path to session.log]
|
||||
Output filtering: enabled
|
||||
Auto-resume: enabled
|
||||
|
||||
I'll maintain your session state across resets. Long sessions won't lose context.
|
||||
```
|
||||
|
||||
Then immediately initialise `session.log` with the current timestamp, branch, and directory.
|
||||
|
||||
---
|
||||
|
||||
## Output Structure
|
||||
|
||||
### On activation
|
||||
|
||||
```
|
||||
Context Mode active.
|
||||
Session log initialised at: [path]
|
||||
Output filtering: enabled
|
||||
Auto-resume: enabled
|
||||
I'll maintain your session state across resets. Long sessions won't lose context.
|
||||
```
|
||||
|
||||
### On command execution (filtered output format)
|
||||
|
||||
```
|
||||
COMMAND: npm test
|
||||
STATUS: exit 1 — failed
|
||||
SUMMARY: 47 tests passed, 3 failed in auth.test.ts
|
||||
ERRORS: Error: Expected 200, received 401 (line 84)
|
||||
Error: Token not found in response (line 112)
|
||||
TAIL:
|
||||
✓ login with valid credentials (23ms)
|
||||
✓ logout clears session (11ms)
|
||||
✗ refresh token after expiry
|
||||
...
|
||||
```
|
||||
|
||||
### On reset / new session (resume announcement)
|
||||
|
||||
```
|
||||
Resuming session.
|
||||
|
||||
Branch: feature/auth-refresh
|
||||
Last working on: Fixing token refresh logic in auth.service.ts
|
||||
Files edited: src/auth/auth.service.ts, src/auth/auth.test.ts
|
||||
Tasks pending: [ ] Fix failing test on line 112
|
||||
[ ] Run full test suite once fix is applied
|
||||
Last prompt: "The refresh token test is still failing — look at the 401 handling"
|
||||
|
||||
Continuing from where we left off.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CLAUDE.md Installation Text
|
||||
|
||||
After activating Context Mode for the session, provide the user with the exact text to add to their `CLAUDE.md` to make it permanent across all sessions:
|
||||
|
||||
````
|
||||
```
|
||||
## Context Mode
|
||||
|
||||
Context Mode is always active in this project.
|
||||
|
||||
### Output Filtering
|
||||
Before any command output enters context, filter it to:
|
||||
- Last 10 lines of stdout
|
||||
- Any lines containing: error, warn, fail, exception, traceback, fatal (case-insensitive)
|
||||
- Exit code
|
||||
- One-line summary of what the command did
|
||||
|
||||
Use this format for filtered output:
|
||||
COMMAND: [command]
|
||||
STATUS: [exit code — success/failed]
|
||||
SUMMARY: [one sentence]
|
||||
ERRORS: [error lines or "none"]
|
||||
TAIL: [last 10 lines]
|
||||
|
||||
### Session Log
|
||||
Maintain a running session log at ./session.log. Write to it after every file edit and every command run. Track: files edited, commands run, tasks in progress, last user prompt, last action taken. Format defined in Context Mode skill.
|
||||
|
||||
### Auto-Resume
|
||||
At the start of every new session, check for ./session.log. If it exists, read it and announce the resume state. Continue from the last task in progress without asking for instructions.
|
||||
```
|
||||
````
|
||||
|
||||
Tell the user: "Add this to your CLAUDE.md and Context Mode will be active permanently for this project — even after you close and reopen the session."
|
||||
|
||||
---
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] `session.log` was initialised immediately on activation (not deferred)
|
||||
- [ ] Log path shown to user is the absolute path, not relative
|
||||
- [ ] Output filtering is applied on the very next command run — not just announced
|
||||
- [ ] Filtered output format includes: command, status, summary, errors, and tail — all five fields
|
||||
- [ ] Session log tracks all four categories: files edited, commands run, tasks in progress, last prompt
|
||||
- [ ] Resume announcement reads the actual log contents — not a generic template
|
||||
- [ ] On resume, Claude continues the work without prompting the user for instructions
|
||||
- [ ] CLAUDE.md installation text was offered after activation
|
||||
- [ ] Log update rule is clear: "Last User Prompt" and "Last Action Taken" replace previous values, not append
|
||||
|
||||
---
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "Enable context mode"
|
||||
- "Turn on context mode for this session"
|
||||
- "Activate long session mode"
|
||||
- "I keep losing context — fix it"
|
||||
- "Set up session logging"
|
||||
- "Keep track of what you've done so you can resume after a reset"
|
||||
- "Enable output filtering to save context"
|
||||
- "Set up auto-resume so we don't lose our place"
|
||||
@@ -0,0 +1,186 @@
|
||||
---
|
||||
name: email-triage
|
||||
description: Reads your Gmail inbox for a configurable window (default: last 8 hours) and surfaces only what needs action — replies, decisions, or follow-up. Filters out receipts, notifications, newsletters, and anything that doesn't need you.
|
||||
---
|
||||
|
||||
# Email Triage
|
||||
|
||||
## The Problem
|
||||
|
||||
Most of us spend real time triaging email that could be sorted automatically. Scrolling through a mixed inbox of newsletters, order confirmations, Jira notifications, and actual human asks is a tax on focus. The 40 emails since lunch contain maybe 4 that actually need you — this skill finds those 4.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
| Requirement | Details |
|
||||
|-------------|---------|
|
||||
| Gmail connector | Must be active in Claude settings (Settings → Connectors → Gmail) |
|
||||
| Gmail account | The account you want triaged |
|
||||
|
||||
If the Gmail connector is not connected, Claude will prompt you to connect it before proceeding.
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Required | Default | Notes |
|
||||
|-------|----------|---------|-------|
|
||||
| Time window | No | Last 8 hours | Accepts: "last 8 hours", "last 24h", "today", "since Monday", "last 3 days" |
|
||||
| Always-include senders | No | None | Specific names or email addresses that always surface, regardless of content |
|
||||
| Always-ignore senders | No | None | Domains or addresses to always suppress (e.g. noreply@*, jira@company.com) |
|
||||
| Focus area | No | None | Optional context: "focus on anything from clients" or "flag anything about the launch" |
|
||||
|
||||
## What Gets Filtered Out
|
||||
|
||||
Claude suppresses the following categories. They are counted in the summary but not shown:
|
||||
|
||||
- Order confirmations and shipping notifications
|
||||
- Marketing and promotional emails (including "one-time" offer emails)
|
||||
- Newsletter subscriptions and digest emails
|
||||
- Automated system notifications (monitoring alerts, CI/CD, build reports)
|
||||
- Calendar invites that have already been accepted or declined
|
||||
- Read receipts and delivery confirmations
|
||||
- Social media notifications (LinkedIn, Twitter/X, etc.)
|
||||
- Internal ticket updates unless the ticket is assigned to you and requires action
|
||||
- Bank and financial statements (surfaced count only, not content)
|
||||
|
||||
## What Gets Surfaced
|
||||
|
||||
Claude surfaces only emails that meet one or more of these criteria:
|
||||
|
||||
- A human is waiting for a reply
|
||||
- A decision is being requested
|
||||
- There is a deadline or time-sensitive ask, explicit or implied
|
||||
- The sender is someone who does not usually email you (potential priority signal)
|
||||
- The email is from a sender in your always-include list
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
## Inbox Triage — [Time window] | [Date], [Time]
|
||||
**Total emails scanned:** X | **Actionable:** Y | **Filtered out:** Z
|
||||
|
||||
---
|
||||
|
||||
### 🔴 High Priority — Needs reply or decision today
|
||||
|
||||
**From:** [Name] <email@domain.com>
|
||||
**Subject:** [Subject line]
|
||||
**Received:** [Time, e.g. 2:14 PM]
|
||||
**What they need:** [One sentence — the actual ask, not a summary of the email]
|
||||
**Reply starter:** "[A draft opener they can continue — 1 sentence max]"
|
||||
|
||||
---
|
||||
|
||||
**From:** [Name] <email@domain.com>
|
||||
**Subject:** [Subject line]
|
||||
**Received:** [Time]
|
||||
**What they need:** [One sentence]
|
||||
**Reply starter:** "[Draft opener]"
|
||||
|
||||
---
|
||||
|
||||
### 🟡 Medium Priority — Reply within 24–48h
|
||||
|
||||
**From:** [Name] <email@domain.com>
|
||||
**Subject:** [Subject line]
|
||||
**Received:** [Time]
|
||||
**What they need:** [One sentence]
|
||||
**Reply starter:** "[Draft opener]" *(or "No reply needed — action only: [what to do]")*
|
||||
|
||||
---
|
||||
|
||||
### 🟢 FYI — Worth knowing, no action required
|
||||
|
||||
- **[Name]** re: [Subject] — [One-line summary of why it might be relevant]
|
||||
- **[Name]** re: [Subject] — [One-line summary]
|
||||
|
||||
---
|
||||
|
||||
### ⚪ Filtered Out — [Z emails]
|
||||
Receipts: X | Newsletters: X | Notifications: X | Other automated: X
|
||||
*(No action needed — not shown in detail)*
|
||||
```
|
||||
|
||||
## Instructions for Claude
|
||||
|
||||
### Step 1 — Connect and confirm the time window
|
||||
|
||||
Confirm the Gmail connector is active. Parse the requested time window and translate it to an exact datetime range (e.g. "last 8 hours" = [current time minus 8 hours] to now). State the window at the top of the output.
|
||||
|
||||
### Step 2 — Read the inbox
|
||||
|
||||
Fetch emails from the inbox for the specified time window. Include: sender name, sender email, subject, received time, and email body (or first 500 words if long). Do not fetch emails older than the window.
|
||||
|
||||
### Step 3 — Apply ignore rules
|
||||
|
||||
If the user specified always-ignore senders or domains, suppress those immediately. If no ignore list was given, apply standard suppression (see What Gets Filtered Out). Track counts for the filtered summary.
|
||||
|
||||
### Step 4 — Classify each remaining email
|
||||
|
||||
For each non-suppressed email, classify into one of four categories:
|
||||
|
||||
- **High Priority**: A human is waiting on a reply today, or there is an explicit deadline within 24 hours
|
||||
- **Medium Priority**: A reply is needed but not urgently, or there is an implicit ask without a hard deadline
|
||||
- **FYI**: No action needed, but the user would likely want to know about it
|
||||
- **Filtered Out**: Falls into a suppressed category — add to count, do not show
|
||||
|
||||
Apply the always-include list after classification: any email from a flagged sender surfaces regardless of category, with its actual classification.
|
||||
|
||||
### Step 5 — Write the "What they need" line
|
||||
|
||||
This is the highest-value part of the output. Write exactly one sentence that captures the actual ask — not a summary of the email, the ask.
|
||||
|
||||
Bad: "Sarah sent an email about the Q3 report."
|
||||
Good: "Sarah needs your sign-off on the Q3 report before she sends it to the board at 5 PM."
|
||||
|
||||
If there is no clear ask, it is probably FYI or filtered out.
|
||||
|
||||
### Step 6 — Write the reply starter
|
||||
|
||||
For High and Medium priority emails, write a one-sentence reply opener. The opener should:
|
||||
- Match the tone of the sender (formal vs. casual)
|
||||
- Acknowledge the ask directly
|
||||
- Be something the user can actually send with minimal editing
|
||||
|
||||
Example: "Thanks for flagging this — let me check with the team and get back to you by EOD."
|
||||
|
||||
If the email requires an action rather than a reply (e.g. "please approve this expense"), write: "No reply needed — action only: [describe the action]."
|
||||
|
||||
### Step 7 — Assemble and deliver the output
|
||||
|
||||
Use the output format exactly as specified. Do not add extra sections, editorialise, or explain your reasoning. The output should be scannable in under 60 seconds.
|
||||
|
||||
### Step 8 — Offer next steps
|
||||
|
||||
After the triage output, offer one of:
|
||||
- "Want me to draft replies to any of these?"
|
||||
- "Say 'reply to [name]' and I'll draft it."
|
||||
|
||||
Keep this to one line. Do not elaborate.
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] Time window was applied correctly — no emails outside the window are included
|
||||
- [ ] Gmail connector was confirmed active before reading
|
||||
- [ ] Every High Priority email has a specific, concrete "What they need" sentence — not a vague summary
|
||||
- [ ] Reply starters match the tone of the original email (formal/informal)
|
||||
- [ ] Filtered-out count is accurate and broken down by category
|
||||
- [ ] FYI section contains only emails with no action required — nothing actionable is buried here
|
||||
- [ ] Always-include senders surfaced regardless of category
|
||||
- [ ] Always-ignore senders/domains are fully suppressed
|
||||
- [ ] Output is scannable — no unnecessary prose, no padding
|
||||
- [ ] Financial statements and sensitive content were counted but not shown in full
|
||||
|
||||
## Dispatch / Mobile Usage
|
||||
|
||||
This skill works from the Claude mobile app (Dispatch). On mobile, the output renders cleanly with the emoji priority markers serving as visual anchors for quick scanning. Recommended mobile trigger: "Check my emails" or "/email-triage".
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- `/email-triage`
|
||||
- "Check my emails"
|
||||
- "What emails need my attention?"
|
||||
- "Triage my inbox for the last 8 hours"
|
||||
- "What came in since this morning?"
|
||||
- "Any urgent emails I need to deal with?"
|
||||
- "Triage my inbox — ignore anything from Jira and the marketing domain"
|
||||
- "Check emails from the last 24 hours, flag anything from [client name]"
|
||||
- "What do I need to reply to today?"
|
||||
@@ -0,0 +1,198 @@
|
||||
---
|
||||
name: morning-intelligence
|
||||
description: "Run a 15-question interview to capture your role, topics, sources, exclusions, and format preferences — then write a master prompt you can drop into a scheduled task or Claude Code Routine to get a personalised news brief every morning. Use when asked to set up a morning intelligence brief, build a morning news prompt, or create a personalised news briefing."
|
||||
---
|
||||
|
||||
# Morning Intelligence Skill
|
||||
|
||||
Write the prompt that writes your briefing. A 15-question interview extracts your exact context — role, topics, sources, exclusions, format, recency — then produces a single master prompt you can paste into a scheduled task or Claude Code Routine and never touch again.
|
||||
|
||||
> **Pro tip:** Run this interview with Opus for the best output. Opus asks sharper follow-up questions and writes a tighter master prompt.
|
||||
|
||||
> **Credit:** Originally created by Ashwin Francis (Cash&Cache) — adapted and extended for this library.
|
||||
|
||||
---
|
||||
|
||||
## Required Inputs
|
||||
|
||||
No inputs required upfront. The skill runs the interview first.
|
||||
|
||||
If the user has already provided context (e.g. pasted a role description or topic list), absorb it and skip those questions in the interview — don't ask for information already given.
|
||||
|
||||
---
|
||||
|
||||
## How the Interview Works
|
||||
|
||||
Run questions **one at a time** (or in small groups of 2–3 where they're closely related). Don't dump all 15 at once. Wait for each answer before proceeding. Ask natural follow-ups where the answer is vague.
|
||||
|
||||
### Interview Questions
|
||||
|
||||
**Block 1 — Who you are and how you read**
|
||||
|
||||
1. What is your role, and what lens do you read news through? (e.g. "Head of Product at a B2B SaaS — I read for competitive moves, AI tooling, and enterprise buying signals.")
|
||||
2. What are the 3–5 topics you always want covered? Be specific — "AI" is too broad; "AI applied to enterprise software" is better.
|
||||
3. What are 2–3 topics you actively want filtered out — things that waste your time every morning?
|
||||
|
||||
**Block 2 — Sources and signals**
|
||||
|
||||
4. Which publications, newsletters, or outlets do you trust most? (Examples: The Information, TLDR, Benedict Evans, Stratechery, FT, specific subreddits)
|
||||
5. Are there any Twitter/X accounts, Substack writers, or niche sources that are must-reads for you specifically?
|
||||
6. Is there any geography that matters — are you focused on a specific country, region, or market?
|
||||
|
||||
**Block 3 — Story type and recency**
|
||||
|
||||
7. What mix of story types do you want? Rank or weight these: breaking news / in-depth analysis / opinion / data & research / product launches & announcements.
|
||||
8. How fresh does the content need to be? Only today's news? Last 24 hours? Last 48 hours? Or are you okay with "last few days" if a story is important enough?
|
||||
|
||||
**Block 4 — Format and time**
|
||||
|
||||
9. How do you want the brief formatted? Options: bullet list by topic / short narrative paragraphs / a digest with headlines + 1-line summaries / a table / mixed.
|
||||
10. What's your reading time budget in the morning? 5 minutes (tight digest) / 10 minutes (fuller brief) / 15 minutes (comprehensive).
|
||||
|
||||
**Block 5 — This week specifically**
|
||||
|
||||
11. Is there anything you're tracking this week in particular — a specific company, deal, product launch, regulatory development, or ongoing story?
|
||||
|
||||
**Block 6 — Follow-up clarification (questions 12–15)**
|
||||
|
||||
Based on the answers above, ask 4 targeted follow-up questions to sharpen ambiguities. Examples of what to probe:
|
||||
|
||||
- If a topic is still broad: "You said [topic] — do you want the technical angle, the business/market angle, or both?"
|
||||
- If sources are vague: "When you say [publication], do you want everything from them or only specific sections/writers?"
|
||||
- If format is unclear: "You want bullets — should each topic have its own section with 3–5 bullets, or one flat list of all stories?"
|
||||
- If recency conflicts with format: "You want only today's news but a comprehensive 15-minute brief — on slow news days, should I go deeper on one story or pull from the last 48 hours to fill it out?"
|
||||
- If exclusions are vague: "You said no [topic] — does that include adjacent topics like [related thing], or strictly [topic]?"
|
||||
|
||||
Use your judgement on which 4 are most worth asking given the actual answers.
|
||||
|
||||
---
|
||||
|
||||
## Output Structure
|
||||
|
||||
After the interview is complete, produce three things in order:
|
||||
|
||||
### 1. Summary of What You Told Me
|
||||
|
||||
A brief summary of the interview, clustered into thematic pillars. This lets the user verify the master prompt will be accurate before it's written.
|
||||
|
||||
```
|
||||
WHAT I HEARD
|
||||
────────────
|
||||
Role lens: [1 sentence]
|
||||
Core topics: [Pillar 1] · [Pillar 2] · [Pillar 3]
|
||||
Exclusions: [Topic A], [Topic B]
|
||||
Sources: [List]
|
||||
Story mix: [e.g. 60% analysis, 30% news, 10% data]
|
||||
Recency: [e.g. Last 24 hours, today only for breaking]
|
||||
Format: [e.g. Bullets by topic, ~10 min read]
|
||||
This week: [Specific tracking items]
|
||||
```
|
||||
|
||||
Confirm: "Does this look right? I'll write the master prompt based on this."
|
||||
|
||||
---
|
||||
|
||||
### 2. The Master Prompt
|
||||
|
||||
Formatted and ready to paste. Start with a markdown code block so the user can copy it cleanly.
|
||||
|
||||
````
|
||||
```
|
||||
MORNING INTELLIGENCE BRIEF — MASTER PROMPT
|
||||
==========================================
|
||||
|
||||
You are an intelligence analyst briefing [ROLE] at the start of their day.
|
||||
|
||||
TASK
|
||||
Generate a personalised morning news brief covering the following.
|
||||
|
||||
TOPICS TO COVER
|
||||
1. [Topic / Pillar 1] — focus on [angle]
|
||||
2. [Topic / Pillar 2] — focus on [angle]
|
||||
3. [Topic / Pillar 3] — focus on [angle]
|
||||
[add pillars as needed]
|
||||
|
||||
NEVER INCLUDE
|
||||
- [Excluded topic 1]
|
||||
- [Excluded topic 2]
|
||||
- [Excluded topic 3]
|
||||
|
||||
PREFERRED SOURCES (prioritise these)
|
||||
[Source 1], [Source 2], [Source 3], [Source 4]
|
||||
|
||||
STORY TYPE MIX
|
||||
[e.g. Prioritise analysis and data-driven pieces. Include breaking news only if significant. Skip opinion unless it's from [specific writer].]
|
||||
|
||||
RECENCY
|
||||
[e.g. Cover only the last 24 hours. For ongoing stories I'm tracking, include relevant developments from the last 48 hours.]
|
||||
|
||||
CURRENTLY TRACKING THIS WEEK
|
||||
[Specific story / company / topic the user flagged]
|
||||
|
||||
FORMAT
|
||||
[e.g. Organise by topic. Under each topic: 2–4 bullet points. Each bullet: headline + 1–2 sentence summary + source name. End with a "What to watch today" section: 2–3 sentences on what matters most today.]
|
||||
|
||||
LENGTH
|
||||
Target a [5/10/15]-minute read.
|
||||
|
||||
TONE
|
||||
Analyst voice. No fluff. Lead with the signal, not the noise. If something is uncertain or based on incomplete reporting, flag it as such.
|
||||
```
|
||||
````
|
||||
|
||||
---
|
||||
|
||||
### 3. Setup Guide
|
||||
|
||||
A short section below the master prompt:
|
||||
|
||||
```
|
||||
HOW TO USE THIS PROMPT
|
||||
──────────────────────
|
||||
|
||||
OPTION A — Cowork Scheduled Tasks (Claude Pro/Max)
|
||||
Requires: Desktop app open at scheduled time
|
||||
1. Open Claude desktop → Cowork → Scheduled Tasks
|
||||
2. Create a new task, set your time (e.g. 7:00 AM)
|
||||
3. Paste the master prompt as the task content
|
||||
4. Save. It will run every morning when your desktop app is open.
|
||||
|
||||
OPTION B — Claude Code Routines (runs in the cloud)
|
||||
Requires: Claude Code with Routines access
|
||||
Advantage: Runs without your laptop being on
|
||||
1. In your project root, create or open .claude/routines.json
|
||||
2. Add a new routine with a cron schedule (e.g. "0 7 * * *" for 7 AM daily)
|
||||
3. Set the prompt field to the master prompt above
|
||||
4. Commit and push — Claude Code will run it on schedule.
|
||||
|
||||
UPDATING YOUR BRIEF
|
||||
When your focus shifts, re-run this skill. The interview takes 5–10 minutes
|
||||
and produces a new master prompt to replace the old one.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] Every interview question was asked — none skipped unless the user already provided the answer
|
||||
- [ ] The "What I Heard" summary was shown and confirmed before writing the master prompt
|
||||
- [ ] The master prompt uses specific topic angles, not vague category names (not "AI" — "AI applied to enterprise software")
|
||||
- [ ] Exclusions are explicitly stated in the master prompt with a NEVER INCLUDE section
|
||||
- [ ] Sources are listed in order of preference, not as a flat unordered list
|
||||
- [ ] Story type mix is written as a directive, not just a list
|
||||
- [ ] Recency instruction handles the edge case of slow news days
|
||||
- [ ] Format instruction is precise enough that a different AI could follow it correctly
|
||||
- [ ] The master prompt is inside a code block so it copies cleanly
|
||||
- [ ] Both setup options (Cowork and Claude Code Routines) are included
|
||||
|
||||
---
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "Set up my morning intelligence brief"
|
||||
- "Build me a morning news prompt"
|
||||
- "Interview me for a morning briefing skill"
|
||||
- "I want to start every day with a personalised news digest"
|
||||
- "Help me set up a daily AI news brief"
|
||||
- "Create a scheduled morning news prompt for me"
|
||||
- "Build me a prompt for my daily briefing routine"
|
||||
@@ -0,0 +1,531 @@
|
||||
---
|
||||
name: aeo-optimizer
|
||||
description: "Optimize an article for Answer Engine Optimization (AEO) — restructuring content so AI engines like ChatGPT, Perplexity, and Claude can extract, quote, and cite it. Rewrites headings as questions, drops 50-80 word answer capsules, audits paragraph length, and flags trust signals. Use when asked to AEO-optimize, make content AI-readable, improve AI citation chances, or adapt an article for answer engines."
|
||||
---
|
||||
|
||||
# AEO Optimizer Skill
|
||||
|
||||
AEO — Answer Engine Optimization — is the discipline of structuring content so that AI engines (ChatGPT, Perplexity, Claude, Gemini) can extract clean, quotable answers and confidently cite your content as a source.
|
||||
|
||||
Most articles are written for humans who scroll, skim, and click. AI engines don't scroll — they scan for extractable answer units. They look for short, self-contained answer blocks sitting directly beneath a clear question heading. If they can't find those, they either skip the content or paraphrase it poorly. This skill fixes that.
|
||||
|
||||
---
|
||||
|
||||
## The AEO Problem
|
||||
|
||||
Here is what AI engines are scanning for, and what most articles fail to provide:
|
||||
|
||||
| What AI engines want | What most articles deliver |
|
||||
|---|---|
|
||||
| H2 = a direct question ("What is X?") | H2 = a vague topic label ("About X" or "Understanding X") |
|
||||
| 50-80 word answer capsule immediately under the heading | Long intro paragraphs before the actual answer |
|
||||
| No links inside the answer block | Inline links that break extractability |
|
||||
| ≤3 sentences per paragraph | Dense 6-8 sentence paragraphs |
|
||||
| Named frameworks, original data, first-person experience | Generic statements with no attribution or specificity |
|
||||
| Consistent question-answer-expand structure throughout | Inconsistent structure that varies section by section |
|
||||
|
||||
When an AI engine cannot cleanly extract a 50-80 word answer, it either skips the article or provides a vague paraphrase without a citation link. AEO optimization removes those barriers.
|
||||
|
||||
---
|
||||
|
||||
## Required Inputs
|
||||
|
||||
Claude will ask for these if not provided:
|
||||
|
||||
| Input | Required | Notes |
|
||||
|---|---|---|
|
||||
| Article content | Yes | Paste the full draft text, or provide a URL Claude can fetch |
|
||||
| Target audience | No | Helps calibrate question phrasing — e.g. "beginner founders" vs "senior engineers" |
|
||||
| Primary keyword or topic | No | If provided, Claude ensures H2 questions cover it directly |
|
||||
| Existing URL (if published) | No | Used in the audit report to note the live page |
|
||||
| Preserve exact section order | No | Defaults to yes — Claude rewrites in place, doesn't restructure |
|
||||
|
||||
If providing a URL instead of pasted text, Claude will fetch the page content. Note: paywalled or JavaScript-rendered articles may require manual paste.
|
||||
|
||||
---
|
||||
|
||||
## Output Structure
|
||||
|
||||
Claude produces two deliverables in sequence:
|
||||
|
||||
### Deliverable 1 — AEO-Ready Article
|
||||
|
||||
The full rewritten article with:
|
||||
- All H2s rewritten as direct questions
|
||||
- 50-80 word answer capsule inserted directly beneath each H2
|
||||
- Paragraphs trimmed to ≤3 sentences where they exceeded that
|
||||
- Trust signals preserved and lightly emphasized
|
||||
- No links inside any answer capsule
|
||||
- Original voice and structure maintained — this is an optimization, not a rewrite
|
||||
|
||||
**Format:**
|
||||
|
||||
```markdown
|
||||
# [Original H1 title — unchanged unless it needs question format]
|
||||
|
||||
[Introduction — keep as-is or trim to ≤3 sentences. Add a "What this covers:" summary if intro is >150 words.]
|
||||
|
||||
## [H2 rewritten as a direct question?]
|
||||
|
||||
[Answer capsule — 50-80 words, no links, self-contained, answers the question completely on its own.]
|
||||
|
||||
[Rest of the section body — expanded explanation, examples, data, links allowed here]
|
||||
|
||||
## [Next H2 as a direct question?]
|
||||
|
||||
[Answer capsule — 50-80 words, no links]
|
||||
|
||||
[Section body]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Deliverable 2 — AEO Audit Report
|
||||
|
||||
Structured report showing all changes made and signals identified.
|
||||
|
||||
**Format:**
|
||||
|
||||
---
|
||||
|
||||
## AEO Audit Report
|
||||
|
||||
**Article:** [Title]
|
||||
**URL:** [If provided]
|
||||
**Audit date:** [Today's date]
|
||||
**AEO readiness score (before):** [X/10]
|
||||
**AEO readiness score (after):** [X/10]
|
||||
|
||||
---
|
||||
|
||||
### Heading Rewrites
|
||||
|
||||
| Original H2 | Rewritten H2 | Change type |
|
||||
|---|---|---|
|
||||
| Understanding Content Strategy | What is content strategy and why does it matter? | Topic label → direct question |
|
||||
| The Benefits of X | What are the main benefits of X? | Vague noun phrase → question |
|
||||
| How We Do It at [Company] | How does [Company] approach X? | First-person → question format |
|
||||
|
||||
---
|
||||
|
||||
### Answer Capsule Placements
|
||||
|
||||
For each section, confirm capsule word count is within 50-80 words:
|
||||
|
||||
| Section | Capsule word count | Links removed from capsule | Status |
|
||||
|---|---|---|---|
|
||||
| What is content strategy...? | 64 words | 2 links removed | OK |
|
||||
| How do you build a content calendar? | 71 words | 0 links (none were present) | OK |
|
||||
| What tools do content teams use? | 58 words | 1 link removed | OK |
|
||||
|
||||
---
|
||||
|
||||
### Paragraph Length Audit
|
||||
|
||||
| Section | Original max paragraph (sentences) | Action taken |
|
||||
|---|---|---|
|
||||
| Introduction | 6 sentences | Split into 2 paragraphs |
|
||||
| Section 2 body | 4 sentences | Trimmed to 3 |
|
||||
| Section 4 body | 2 sentences | No change needed |
|
||||
|
||||
**Paragraphs flagged as too long (before optimization):** [N]
|
||||
**Paragraphs within ≤3 sentences (after optimization):** [all]
|
||||
|
||||
---
|
||||
|
||||
### Trust Signal Inventory
|
||||
|
||||
Trust signals are the elements AI engines treat as credibility markers — original data, named frameworks, first-person experience, and specific attributions. These make AI engines more likely to cite rather than paraphrase.
|
||||
|
||||
| Signal type | Found in article | Example | AEO value |
|
||||
|---|---|---|---|
|
||||
| Original data / research | Yes | "Our analysis of 400 posts showed..." | High — cite-worthy claim |
|
||||
| Named framework | Yes | "The RICE scoring model" | High — search anchor |
|
||||
| First-person experience | Yes | "After running 3 content audits..." | Medium — authority signal |
|
||||
| Named expert / quote | No | — | Recommend adding |
|
||||
| Specific numbers / stats | Yes | "34% increase in organic traffic" | High — extractable fact |
|
||||
| Date-stamped content | No | — | Recommend adding publication date |
|
||||
| Case study reference | Yes | "At Acme Corp, we ran..." | High — concrete example |
|
||||
|
||||
**Trust signals present:** [N]
|
||||
**Recommended additions:** [list any gaps]
|
||||
|
||||
---
|
||||
|
||||
### AEO Scoring Rubric
|
||||
|
||||
| Criterion | Before | After |
|
||||
|---|---|---|
|
||||
| H2s as direct questions (% of total) | [X%] | [X%] |
|
||||
| Answer capsule present under each H2 | No | Yes |
|
||||
| Capsules within 50-80 words | N/A | [X/N sections] |
|
||||
| No links inside capsules | N/A | Yes |
|
||||
| Paragraphs ≤3 sentences | [X%] | [X%] |
|
||||
| Trust signals present | [N] | [N] |
|
||||
| **Total score** | **[X/10]** | **[X/10]** |
|
||||
|
||||
---
|
||||
|
||||
### Recommended Next Steps
|
||||
|
||||
1. [Any remaining gaps — e.g. "Section 4 capsule is 88 words — trim by 10"]
|
||||
2. [Structural suggestions — e.g. "Add a FAQ section at the end for high-volume PAA questions"]
|
||||
3. [Missing trust signals — e.g. "Add a publication date and last-updated date for freshness signals"]
|
||||
4. [Schema markup suggestion if applicable — FAQ schema, HowTo schema, etc.]
|
||||
|
||||
---
|
||||
|
||||
*End of AEO Audit Report*
|
||||
|
||||
---
|
||||
|
||||
## How Claude Should Execute This Skill
|
||||
|
||||
### Step 1 — Ingest the article
|
||||
|
||||
Accept the content as either:
|
||||
- **Pasted text:** Treat as-is. Do not attempt to fetch a URL if text is pasted.
|
||||
- **URL:** Fetch the page. Extract the main article body — ignore nav, sidebars, footers, and ad blocks. If the page is JavaScript-rendered and fetch returns only a shell, ask the user to paste the text instead.
|
||||
|
||||
Count the headings. Note the number of H2s, H3s, and H1s. This sets expectations for how many capsules will be written.
|
||||
|
||||
### Step 2 — Assess AEO readiness before touching anything
|
||||
|
||||
Before rewriting, score the article on the AEO rubric (see Deliverable 2 scoring table). This gives the user a before/after comparison and helps Claude identify where to focus effort.
|
||||
|
||||
Run through each criterion and note the count:
|
||||
- How many H2s are already in question format? (count ones that end with "?")
|
||||
- Does any section already have a 50-80 word self-contained answer block?
|
||||
- What is the average and maximum paragraph length in sentences?
|
||||
- How many trust signals are present? (scan for numbers, named frameworks, first-person phrases, quotes)
|
||||
|
||||
Record the before scores. Do not round up — be honest.
|
||||
|
||||
### Step 3 — Rewrite H2 headings as questions
|
||||
|
||||
For each H2 in the article, rewrite it as a direct question that a real person would ask an AI engine. Guidelines:
|
||||
|
||||
**The question must:**
|
||||
- Be specific enough that the answer could stand alone as a snippet
|
||||
- Use "What", "How", "Why", "When", "Which", or "Who" — not vague gerunds ("Understanding", "Exploring", "Unpacking")
|
||||
- Match the search intent of the original section, not just rephrase it generically
|
||||
- Be 8 words or fewer when possible (longer questions are harder for AI engines to match)
|
||||
|
||||
**Examples of heading transformations:**
|
||||
|
||||
| Before | After |
|
||||
|---|---|
|
||||
| Introduction to Agile | What is Agile methodology? |
|
||||
| Why We Built This | Why did [Company] build [product]? |
|
||||
| The Case for Async Work | Why do distributed teams choose async work? |
|
||||
| Benefits | What are the main benefits of X? |
|
||||
| Tools and Resources | Which tools do [audience] use for X? |
|
||||
| Getting Started | How do you get started with X? |
|
||||
| Common Mistakes | What mistakes do beginners make with X? |
|
||||
| Our Approach | How does [Company/author] approach X? |
|
||||
|
||||
Do not rewrite H3s unless the user requests it. H3s can stay as labels — AI engines primarily anchor on H2s.
|
||||
|
||||
Do not change the H1. The H1 is the article title and SEO title — it follows different rules.
|
||||
|
||||
### Step 4 — Write answer capsules
|
||||
|
||||
For each H2, write a 50-80 word answer capsule to be inserted immediately after the heading and before any existing body text.
|
||||
|
||||
**Capsule rules:**
|
||||
- Must be self-contained — someone reading only the heading + capsule should have a complete, useful answer
|
||||
- No links of any kind inside the capsule (links break AI extractability)
|
||||
- No hedging phrases ("It depends", "There are many factors") — commit to the answer
|
||||
- Use the same voice and terminology as the article — do not change the author's perspective
|
||||
- If the section has an existing strong first paragraph that is already 50-80 words and self-contained, use it as the capsule with minimal edits rather than writing a new one
|
||||
- Count words precisely — under 50 is too thin, over 80 and AI engines may not extract it cleanly
|
||||
|
||||
**Capsule structure options:**
|
||||
|
||||
Option A — Definition then application:
|
||||
```
|
||||
[Concise definition of the concept in 1-2 sentences.] [How it applies in practice, with one specific example or number.] [Why it matters for the reader's situation.]
|
||||
```
|
||||
|
||||
Option B — Direct answer then context:
|
||||
```
|
||||
[Direct answer to the heading question in 1 sentence.] [2-3 sentences of supporting context, specifics, or mechanism.] [Optional: one concrete example or stat.]
|
||||
```
|
||||
|
||||
Option C — How-to opener:
|
||||
```
|
||||
[State the outcome in 1 sentence.] [Steps 1, 2, 3 in compressed form.] [Note on when this applies or what to watch for.]
|
||||
```
|
||||
|
||||
Mark each capsule clearly with an HTML comment so the author knows it was added:
|
||||
```html
|
||||
<!-- AEO Answer Capsule — 64 words -->
|
||||
[capsule text]
|
||||
<!-- End AEO Capsule -->
|
||||
```
|
||||
|
||||
### Step 5 — Audit and trim paragraph length
|
||||
|
||||
Scan every paragraph in the body sections (not the capsules). If a paragraph exceeds 3 sentences:
|
||||
- Split it into two paragraphs at the most natural break
|
||||
- Do not summarise or remove content — just add a paragraph break
|
||||
- If a paragraph is a list in disguise (long run-on sentence with "and", "then", "also"), convert it to a bullet list instead
|
||||
|
||||
Note every change in the audit report's paragraph length table.
|
||||
|
||||
### Step 6 — Identify and flag trust signals
|
||||
|
||||
Scan the full article for trust signals. Do not add trust signals — only identify what exists and flag gaps. Trust signals are:
|
||||
|
||||
| Signal type | What to look for |
|
||||
|---|---|
|
||||
| Original data | "Our data shows", "We analysed X", "In our survey of N..." |
|
||||
| Named frameworks | Any named methodology, model, or system (RICE, Jobs-to-be-Done, etc.) |
|
||||
| First-person experience | "I found", "We ran", "When I built", "After testing..." |
|
||||
| Specific numbers | Percentages, counts, timeframes, dollar amounts |
|
||||
| Expert quotes | Direct quotes attributed to a named person |
|
||||
| Case studies | Named company or project with specific outcomes |
|
||||
| Publication freshness | A visible publish or update date |
|
||||
|
||||
Flag any category with zero signals as a gap. Include specific recommendations for what could be added (e.g. "Add a statistic to the intro — even a well-known industry stat cited correctly adds credibility").
|
||||
|
||||
### Step 7 — Assemble the output
|
||||
|
||||
Produce the two deliverables in this order:
|
||||
|
||||
1. First: the full AEO-ready article. Use the original markdown structure with the changes applied. Make sure capsules have the HTML comment markers.
|
||||
2. Second: the AEO Audit Report, using the exact table structure from the Output Structure section above.
|
||||
|
||||
Separate the two deliverables with a clear horizontal rule (`---`) and a heading (`## AEO Audit Report`).
|
||||
|
||||
### Step 8 — Optional: FAQ section recommendation
|
||||
|
||||
If the article does not already have a FAQ section, and the topic has obvious high-volume PAA (People Also Ask) questions, recommend adding one. Provide 3-5 suggested FAQ questions in question format with brief capsule answers. Note that FAQ sections with proper schema markup (`FAQPage` JSON-LD) get preferential treatment in both traditional SEO and AI engine extraction.
|
||||
|
||||
---
|
||||
|
||||
## AEO Reference: What Makes a Good Answer Capsule
|
||||
|
||||
This section is reference material — Claude should use it when evaluating capsule quality.
|
||||
|
||||
**Strong capsule (62 words):**
|
||||
> Content strategy is the planning and management of content to achieve specific business goals. It defines what to publish, for whom, through which channels, and how often. A strong content strategy starts with audience research, maps content to stages of the buyer journey, and includes a measurement framework. Without it, content teams produce output without direction — publishing more without knowing whether it drives outcomes.
|
||||
|
||||
Why it works:
|
||||
- Answers the question completely in isolation
|
||||
- No links
|
||||
- Specific enough to be citable (mentions audience research, buyer journey, measurement framework)
|
||||
- Under 80 words
|
||||
|
||||
**Weak capsule (48 words — too short, too vague):**
|
||||
> Content strategy is important for businesses. It helps you plan what content to create. Many companies use content strategy to grow their audience. There are different approaches depending on your goals. It's a broad topic that covers many areas of marketing.
|
||||
|
||||
Why it fails:
|
||||
- Does not complete the answer — "many areas" is not an answer
|
||||
- No specifics, no named concepts
|
||||
- Under 50 words
|
||||
- AI engine would not cite this — it says nothing citable
|
||||
|
||||
---
|
||||
|
||||
## Quality Checks
|
||||
|
||||
Before marking this task complete, verify each item:
|
||||
|
||||
- [ ] Every H2 in the article is now a direct question ending with "?"
|
||||
- [ ] Every question-format H2 has an answer capsule immediately below it (no intervening text)
|
||||
- [ ] Every capsule is between 50 and 80 words — count precisely, not approximately
|
||||
- [ ] No links appear inside any capsule block
|
||||
- [ ] Every capsule has the HTML comment markers noting word count
|
||||
- [ ] Paragraphs throughout the article body are ≤3 sentences (flag any exceptions in the report)
|
||||
- [ ] The H1 title is unchanged
|
||||
- [ ] H3s are unchanged (unless user requested otherwise)
|
||||
- [ ] Original voice, tone, and terminology are preserved — this is optimization, not ghostwriting
|
||||
- [ ] Trust signal inventory table is populated with actual examples from the text, not generic placeholders
|
||||
- [ ] Gaps in trust signals are noted with specific recommendations, not just "add more data"
|
||||
- [ ] Before and after AEO scores are both present in the audit report
|
||||
- [ ] Heading rewrites table is complete — one row per H2
|
||||
- [ ] Paragraph length audit table is complete — covers all sections
|
||||
- [ ] Any FAQ section recommendation is based on real PAA-style questions for the topic, not invented ones
|
||||
- [ ] Both deliverables (article + audit report) are present in the response
|
||||
- [ ] Total word count of the rewritten article is within ±10% of the original (optimization, not expansion)
|
||||
|
||||
---
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "AEO optimize this article"
|
||||
- "Make this content AI-readable"
|
||||
- "Rewrite my headings as questions and add answer capsules"
|
||||
- "Optimize this for ChatGPT and Perplexity to cite"
|
||||
- "Run an AEO audit on this draft"
|
||||
- "Make this article get picked up by AI search"
|
||||
- "I want Perplexity to cite my content — can you fix this article?"
|
||||
- "Turn these headings into questions and add short answer blocks"
|
||||
- "Can you add answer capsules under each section?"
|
||||
- "Audit this for answer engine optimization"
|
||||
- "My content isn't showing up in AI answers — fix the structure"
|
||||
- "AEO this" [followed by article text or URL]
|
||||
- "Optimize for AI citation"
|
||||
- "Make each section self-contained for AI extraction"
|
||||
|
||||
---
|
||||
|
||||
## Appendix: AEO vs SEO — Key Differences
|
||||
|
||||
This is useful context Claude can share with users who are unfamiliar with AEO:
|
||||
|
||||
| Dimension | SEO (Search Engine Optimization) | AEO (Answer Engine Optimization) |
|
||||
|---|---|---|
|
||||
| Target | Google's ranking algorithm | AI engine extraction models |
|
||||
| Primary signal | Backlinks, authority, keyword density | Structured Q&A, answer capsule clarity |
|
||||
| Content format | Long-form, comprehensive coverage | Question-first, capsule-first, then expand |
|
||||
| Heading style | Keyword-rich labels ("Best Project Management Tools") | Direct questions ("What are the best project management tools?") |
|
||||
| Paragraph length | Not a ranking factor | Short (≤3 sentences) is strongly preferred |
|
||||
| Links in body | Important for authority passing | Links inside answer capsules break extractability |
|
||||
| Trust signals | Domain authority, backlink profile | Named data, frameworks, first-person experience |
|
||||
| Measurement | Organic ranking position, CTR | AI citation frequency, answer box appearances |
|
||||
|
||||
AEO does not replace SEO — it complements it. A well-structured article optimized for AEO will also perform better in traditional search because its structure is clearer and its headings are more specific to user intent.
|
||||
|
||||
---
|
||||
|
||||
## Appendix: Answer Capsule Templates by Content Type
|
||||
|
||||
Not all articles have the same kind of content. Use these capsule templates as starting points based on the section type.
|
||||
|
||||
### "What is X?" sections (definition)
|
||||
|
||||
```
|
||||
[X] is [concise category or type]. It [what it does or how it works] by [mechanism or method].
|
||||
[Why it exists or what problem it solves — 1 sentence.] [One concrete example or real-world application.]
|
||||
```
|
||||
|
||||
Target: 55-70 words. Avoid starting with "X is a type of X" — give immediate signal.
|
||||
|
||||
### "How do you do X?" sections (how-to)
|
||||
|
||||
```
|
||||
To [achieve outcome], [do step A], then [do step B], then [do step C].
|
||||
[The most common mistake or prerequisite — 1 sentence.] [The expected result or timeframe.]
|
||||
```
|
||||
|
||||
Target: 50-65 words. Use active verbs throughout. No links.
|
||||
|
||||
### "Why does X matter?" sections (rationale)
|
||||
|
||||
```
|
||||
[X] matters because [specific reason 1] and [specific reason 2].
|
||||
Without [X], [consequence — ideally quantified or concrete].
|
||||
[Who this is most important for, and under what conditions.]
|
||||
```
|
||||
|
||||
Target: 55-75 words. Specifics outperform generalities here — name numbers when they exist.
|
||||
|
||||
### "What are the benefits of X?" sections (list rationale)
|
||||
|
||||
```
|
||||
The main benefits of [X] are [benefit 1], [benefit 2], and [benefit 3].
|
||||
[Benefit 1] means [specific outcome]. [Benefit 2] enables [specific use case].
|
||||
Together these make [X] valuable for [audience] who need [outcome].
|
||||
```
|
||||
|
||||
Target: 60-80 words. Compress the list into prose — bullet lists inside capsules are less extractable.
|
||||
|
||||
### "Which X should I choose?" sections (comparison/decision)
|
||||
|
||||
```
|
||||
Choose [Option A] when [condition A]. Choose [Option B] when [condition B].
|
||||
The deciding factor is [key variable]. [One sentence on the most common mistake —
|
||||
picking based on the wrong criterion.]
|
||||
```
|
||||
|
||||
Target: 50-70 words. Decision capsules are among the highest-cited by AI engines — they answer the user's actual next question.
|
||||
|
||||
### "When should I X?" sections (timing/trigger)
|
||||
|
||||
```
|
||||
[X] when [specific trigger condition], typically [timeframe or frequency].
|
||||
Early signs that it's time include [signal 1] and [signal 2].
|
||||
Waiting too long often results in [consequence].
|
||||
```
|
||||
|
||||
Target: 45-65 words. Concise is especially important for timing capsules.
|
||||
|
||||
---
|
||||
|
||||
## Appendix: AEO Scoring Rubric — Detailed Criteria
|
||||
|
||||
Use this when producing the before/after score. Each criterion has a maximum contribution to the /10 score.
|
||||
|
||||
| Criterion | Max score | How to assess |
|
||||
|---|---|---|
|
||||
| H2s as direct questions | 2 pts | 2 = all H2s are questions; 1 = majority; 0 = few or none |
|
||||
| Answer capsules present | 2 pts | 2 = every H2 section has a capsule; 1 = some sections; 0 = none |
|
||||
| Capsules within 50-80 words | 1 pt | 1 = all capsules in range; 0 = any over 80 or under 50 |
|
||||
| No links inside capsules | 1 pt | 1 = zero links in any capsule; 0 = any links present |
|
||||
| Paragraphs ≤3 sentences | 2 pts | 2 = all paragraphs compliant; 1 = majority; 0 = widespread violations |
|
||||
| Trust signals present | 2 pts | 2 = 3+ trust signal types; 1 = 1-2 types; 0 = none |
|
||||
|
||||
**Score interpretation:**
|
||||
- 8-10: Strong AEO readiness — well-positioned for AI citation
|
||||
- 5-7: Partial — likely extracted occasionally but inconsistently
|
||||
- 0-4: Low readiness — AI engines will paraphrase at best, skip at worst
|
||||
|
||||
A typical unoptimized article scores 2-4. A well-structured but unoptimized thought leadership piece might score 4-6. After this skill runs, target 8+.
|
||||
|
||||
---
|
||||
|
||||
## Appendix: How Different AI Engines Extract Content
|
||||
|
||||
Understanding how each engine works helps explain the rules behind the skill.
|
||||
|
||||
### ChatGPT (GPT-4 and later) / Bing
|
||||
|
||||
Retrieval-augmented generation with Bing Search integration. When a user asks a question, Bing retrieves pages, then GPT extracts passages. It tends to extract the first plausible answer-shaped block it finds in the page — meaning the capsule directly under the H2 is almost always what gets quoted. It prefers prose over lists for citations (though it reads lists fine).
|
||||
|
||||
**Implication:** Get the capsule under the question-format H2 right. The rest of the section body is bonus context.
|
||||
|
||||
### Perplexity
|
||||
|
||||
Explicitly designed for sourced Q&A. It retrieves 5-10 pages per query and extracts from all of them simultaneously. It shows citations with numbered footnotes. It strongly prefers content that is:
|
||||
- Clearly attributed (author name or publication byline visible)
|
||||
- Recently published or updated (freshness signal)
|
||||
- Structured around the question being asked (heading match)
|
||||
|
||||
**Implication:** Trust signals (author, date) and heading-to-question matching are especially important for Perplexity. Capsules that include specific numbers or named frameworks are more likely to be footnoted.
|
||||
|
||||
### Claude (Anthropic)
|
||||
|
||||
Claude with web search capability (Claude.ai or API with tools) retrieves pages and synthesises across them. Claude prioritises self-contained, complete answers and tends to directly quote capsules that are within the 50-80 word range. Claude is less likely to quote incomplete paragraphs that trail off or rely on surrounding context.
|
||||
|
||||
**Implication:** The self-contained requirement is especially important for Claude citation. If the capsule requires reading the surrounding sentences to make sense, Claude will paraphrase instead of quote.
|
||||
|
||||
### Google Gemini (AI Overviews)
|
||||
|
||||
Integrated into Google Search. Generates AI Overviews for informational queries. Extracts from indexed pages, with preference for pages that already rank well (so SEO and AEO reinforce each other here). Tends to extract bulleted lists and numbered steps for how-to content; extracts definition capsules for "what is" queries.
|
||||
|
||||
**Implication:** For Gemini AI Overviews, structured how-to content with numbered steps in the capsule performs well. Definition capsules should include the category/type as the first word.
|
||||
|
||||
---
|
||||
|
||||
## Appendix: Content Types That Benefit Most from AEO
|
||||
|
||||
Not all content benefits equally. Use this to set expectations with the user about where AEO investment pays off most.
|
||||
|
||||
| Content type | AEO benefit | Reason |
|
||||
|---|---|---|
|
||||
| Glossary or definition articles | Very high | AI engines are constantly answering "what is X?" queries |
|
||||
| How-to guides and tutorials | Very high | Step-by-step content is a primary retrieval target |
|
||||
| Comparison articles ("X vs Y") | High | Decision queries are common AI engine inputs |
|
||||
| FAQ pages | High | Already in question format — just needs capsule discipline |
|
||||
| Research roundups with original data | High | Named statistics are citation anchors |
|
||||
| Thought leadership / opinion pieces | Medium | Opinion is less extractable; add definition and how-to sections |
|
||||
| News and timely content | Medium | AI engines prefer evergreen; but breaking news gets citation bursts |
|
||||
| Case studies | Medium | Specific outcomes are extractable; company-specific context less so |
|
||||
| Creative writing / narrative | Low | Not structured for extraction; AEO rules don't apply |
|
||||
| Product pages / landing pages | Low | Conversion-focused pages are rarely cited by AI engines |
|
||||
|
||||
---
|
||||
|
||||
*Originally created by Gencay (LearnAIwithMe) — adapted and extended for this library.*
|
||||
@@ -0,0 +1,665 @@
|
||||
---
|
||||
name: instagram-post-downloader
|
||||
description: "Download Instagram posts — single images or full carousels — directly from a URL. Fetches high-resolution files from Instagram's CDN, saves them into a named folder, and stitches carousel slides into a single PDF. Supports batch downloading of multiple URLs at once. Use when asked to download, save, or archive an Instagram post, reel thumbnail, or carousel."
|
||||
---
|
||||
|
||||
# Instagram Post Downloader Skill
|
||||
|
||||
Downloads Instagram posts at full resolution from Instagram's CDN — no screenshots, no compression. Handles single images, carousels (multi-slide posts), and Reel cover images. For carousels, produces individual slide files plus a single stitched PDF. Supports batch URLs in one run.
|
||||
|
||||
---
|
||||
|
||||
## PREREQUISITE — Domain Allowlist
|
||||
|
||||
Before this skill can fetch any media, you must add Instagram's CDN domain to Claude Code's allowlist:
|
||||
|
||||
**Settings → Capabilities → Domain allowlist → Add:**
|
||||
```
|
||||
*.cdninstagram.com
|
||||
```
|
||||
|
||||
Without this, all CDN fetch calls will be blocked. If you see a permission error when Claude attempts a fetch to `cdninstagram.com`, this is the fix.
|
||||
|
||||
---
|
||||
|
||||
## Required Inputs
|
||||
|
||||
Claude will ask for these if not provided upfront:
|
||||
|
||||
| Input | Required | Notes |
|
||||
|---|---|---|
|
||||
| Instagram post URL(s) | Yes | One per line, or comma-separated. `https://www.instagram.com/p/XXXX/` or `https://www.instagram.com/reel/XXXX/` format |
|
||||
| Output directory | No | Defaults to `./instagram-downloads/` in the current working directory |
|
||||
| PDF stitch for carousels | No | Defaults to **yes** — produces `carousel.pdf` alongside individual slides |
|
||||
| File naming prefix | No | Optional prefix added before slide filenames, e.g. `brand_` → `brand_slide_01.jpg` |
|
||||
|
||||
**Batch input example:**
|
||||
```
|
||||
https://www.instagram.com/p/ABC123/
|
||||
https://www.instagram.com/p/DEF456/
|
||||
https://www.instagram.com/p/GHI789/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Output Structure
|
||||
|
||||
For each URL processed, Claude creates a folder named after the post caption (first 40 characters, sanitised — spaces become underscores, special characters stripped). If no caption is available, the folder is named after the post shortcode.
|
||||
|
||||
### Single image post
|
||||
|
||||
```
|
||||
instagram-downloads/
|
||||
└── this_is_the_caption_first_40_chars/
|
||||
├── image.jpg
|
||||
└── metadata.txt
|
||||
```
|
||||
|
||||
### Carousel post
|
||||
|
||||
```
|
||||
instagram-downloads/
|
||||
└── carousel_caption_first_40_chars/
|
||||
├── slide_01.jpg
|
||||
├── slide_02.jpg
|
||||
├── slide_03.jpg
|
||||
├── slide_04.jpg
|
||||
├── carousel.pdf ← all slides stitched in order
|
||||
└── metadata.txt
|
||||
```
|
||||
|
||||
### Batch run (3 URLs)
|
||||
|
||||
```
|
||||
instagram-downloads/
|
||||
├── first_post_caption_sanitised/
|
||||
│ ├── image.jpg
|
||||
│ └── metadata.txt
|
||||
├── second_post_carousel_caption/
|
||||
│ ├── slide_01.jpg
|
||||
│ ├── slide_02.jpg
|
||||
│ ├── carousel.pdf
|
||||
│ └── metadata.txt
|
||||
└── third_post_caption_here/
|
||||
├── image.jpg
|
||||
└── metadata.txt
|
||||
```
|
||||
|
||||
### metadata.txt format
|
||||
|
||||
```
|
||||
Post URL: https://www.instagram.com/p/XXXX/
|
||||
Shortcode: XXXX
|
||||
Type: carousel | single_image | reel
|
||||
Slide count: 4 (carousel only)
|
||||
Caption: [full caption text]
|
||||
Username: @username
|
||||
Fetched at: 2026-05-27T14:32:00Z
|
||||
CDN URLs:
|
||||
slide_01.jpg https://scontent.cdninstagram.com/v/...
|
||||
slide_02.jpg https://scontent.cdninstagram.com/v/...
|
||||
```
|
||||
|
||||
### Completion summary (printed to terminal)
|
||||
|
||||
```
|
||||
Instagram Post Downloader — Batch Complete
|
||||
==========================================
|
||||
URLs processed: 3
|
||||
Posts saved: 3
|
||||
Total files: 11 (9 images + 2 PDFs)
|
||||
Skipped: 0
|
||||
Output dir: /Users/you/project/instagram-downloads/
|
||||
|
||||
Results:
|
||||
✓ this_is_the_caption_first_40_chars/ 1 image
|
||||
✓ carousel_caption_first_40_chars/ 4 slides → carousel.pdf
|
||||
✓ third_post_caption_here/ 1 image
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## How Claude Should Execute This Skill
|
||||
|
||||
### Step 1 — Collect and validate inputs
|
||||
|
||||
1. Accept the URL(s) from the user. If the user pastes a comma-separated list, split on commas. If they paste one per line, split on newlines.
|
||||
2. Validate each URL matches `instagram.com/p/`, `instagram.com/reel/`, or `instagram.com/tv/`. Flag malformed URLs before proceeding.
|
||||
3. Confirm the output directory. If none provided, use `./instagram-downloads/` and tell the user.
|
||||
4. Ask about PDF stitching preference only if the user hasn't said either way. Default is yes.
|
||||
|
||||
### Step 2 — For each URL: fetch the post page
|
||||
|
||||
Fetch the Instagram post page HTML:
|
||||
|
||||
```
|
||||
GET https://www.instagram.com/p/{shortcode}/?__a=1&__d=dis
|
||||
```
|
||||
|
||||
Instagram frequently changes its API surface. Use this fallback chain in order:
|
||||
|
||||
**Attempt A — JSON endpoint:**
|
||||
```
|
||||
https://www.instagram.com/p/{shortcode}/?__a=1&__d=dis
|
||||
```
|
||||
Parse the JSON response. Look for `graphql.shortcode_media` or `data.shortcode_media`.
|
||||
|
||||
**Attempt B — Embed page (most reliable):**
|
||||
```
|
||||
https://www.instagram.com/p/{shortcode}/embed/captioned/
|
||||
```
|
||||
Fetch this page's HTML and extract `og:image` meta tags and any `window.__additionalDataLoaded` or `window.__StaticData` JSON blobs embedded in `<script>` tags.
|
||||
|
||||
**Attempt C — oEmbed endpoint:**
|
||||
```
|
||||
https://api.instagram.com/oembed/?url=https://www.instagram.com/p/{shortcode}/&omitscript=true
|
||||
```
|
||||
This returns `thumbnail_url` — useful for single images, but only gives the first frame for carousels.
|
||||
|
||||
**Headers to include on all requests:**
|
||||
```
|
||||
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36
|
||||
Accept-Language: en-US,en;q=0.9
|
||||
Accept: text/html,application/xhtml+xml,application/json
|
||||
```
|
||||
|
||||
### Step 3 — Extract CDN image URLs
|
||||
|
||||
From the fetched data, extract all high-resolution CDN URLs. Instagram CDN URLs follow these patterns:
|
||||
|
||||
```
|
||||
https://scontent.cdninstagram.com/v/...jpg?...
|
||||
https://scontent-lax3-1.cdninstagram.com/v/...jpg?...
|
||||
https://instagram.fXXX1-1.fbcdn.net/v/...jpg?...
|
||||
```
|
||||
|
||||
**For single image posts:**
|
||||
- Extract the single `display_url` or the largest `display_resources` entry (pick the one with the highest `config_width`).
|
||||
|
||||
**For carousel posts:**
|
||||
- Look for `edge_sidecar_to_children.edges[]` in the JSON. Each edge has its own `node.display_url` and `node.display_resources[]`.
|
||||
- Iterate all edges in order. This determines slide numbering.
|
||||
- Pick the highest-resolution variant from each slide's `display_resources` array.
|
||||
|
||||
**For Reels:**
|
||||
- The cover image is extractable the same way as a single image.
|
||||
- The video file itself requires a third-party tool (see Bonus section).
|
||||
|
||||
**If JSON extraction fails**, fall back to scraping `<meta property="og:image">` tags from the page HTML — this gives at least one image URL (the first slide or only image).
|
||||
|
||||
### Step 4 — Sanitise folder name
|
||||
|
||||
Build the folder name from the post caption:
|
||||
1. Take the first 40 characters of the caption.
|
||||
2. Strip all characters that are not alphanumeric, spaces, or hyphens.
|
||||
3. Replace spaces and hyphens with underscores.
|
||||
4. Lowercase the result.
|
||||
5. Strip leading/trailing underscores.
|
||||
6. If the result is empty (e.g. caption was all emoji), use the post shortcode instead.
|
||||
|
||||
```python
|
||||
import re
|
||||
|
||||
def sanitise_folder_name(caption: str, shortcode: str) -> str:
|
||||
truncated = caption[:40]
|
||||
cleaned = re.sub(r'[^a-zA-Z0-9 \-]', '', truncated)
|
||||
underscored = re.sub(r'[\s\-]+', '_', cleaned).strip('_').lower()
|
||||
return underscored if underscored else shortcode
|
||||
```
|
||||
|
||||
### Step 5 — Create output folder structure
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
base_dir = "./instagram-downloads"
|
||||
folder_name = sanitise_folder_name(caption, shortcode)
|
||||
post_dir = os.path.join(base_dir, folder_name)
|
||||
os.makedirs(post_dir, exist_ok=True)
|
||||
```
|
||||
|
||||
If a folder with that name already exists (e.g. running the same URL twice), append the shortcode to avoid collision: `folder_name_SHORTCODE`.
|
||||
|
||||
### Step 6 — Download each image file
|
||||
|
||||
For each CDN URL, download the file with a streaming GET request:
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
def download_file(url: str, dest_path: str) -> bool:
|
||||
headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
|
||||
"Referer": "https://www.instagram.com/",
|
||||
}
|
||||
response = requests.get(url, headers=headers, stream=True, timeout=30)
|
||||
response.raise_for_status()
|
||||
with open(dest_path, "wb") as f:
|
||||
for chunk in response.iter_content(chunk_size=8192):
|
||||
f.write(chunk)
|
||||
return True
|
||||
```
|
||||
|
||||
Name files:
|
||||
- Single image: `image.jpg`
|
||||
- Carousel slides: `slide_01.jpg`, `slide_02.jpg`, ... (zero-padded to 2 digits, or 3 digits if >99 slides)
|
||||
|
||||
Detect file format from the `Content-Type` header or URL extension. Instagram serves JPEG for photos and may serve WebP in some cases — preserve the actual extension.
|
||||
|
||||
### Step 7 — Stitch carousel PDF (if applicable)
|
||||
|
||||
After all slides are downloaded, stitch them into a single PDF using Pillow:
|
||||
|
||||
```python
|
||||
from PIL import Image
|
||||
|
||||
def stitch_to_pdf(image_paths: list[str], output_path: str) -> None:
|
||||
"""
|
||||
Combine a list of image files into a single multi-page PDF.
|
||||
Each image becomes one page. Page size matches the image dimensions.
|
||||
"""
|
||||
images = []
|
||||
for path in sorted(image_paths): # sort ensures slide_01, slide_02, ... order
|
||||
img = Image.open(path).convert("RGB")
|
||||
images.append(img)
|
||||
|
||||
if not images:
|
||||
return
|
||||
|
||||
first = images[0]
|
||||
rest = images[1:]
|
||||
first.save(
|
||||
output_path,
|
||||
format="PDF",
|
||||
save_all=True,
|
||||
append_images=rest,
|
||||
resolution=150.0,
|
||||
)
|
||||
```
|
||||
|
||||
Save as `carousel.pdf` in the post folder. If Pillow is not installed, run `pip install Pillow` first — or instruct the user to do so.
|
||||
|
||||
**Dependency check at start of skill:**
|
||||
```python
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
print("Pillow not installed. Run: pip install Pillow")
|
||||
print("PDF stitching will be skipped. Individual slides will still be downloaded.")
|
||||
skip_pdf = True
|
||||
```
|
||||
|
||||
### Step 8 — Write metadata.txt
|
||||
|
||||
Write a `metadata.txt` file into the post folder with all extracted metadata:
|
||||
|
||||
```python
|
||||
from datetime import datetime, timezone
|
||||
|
||||
def write_metadata(post_dir, post_url, shortcode, post_type, caption, username, cdn_urls):
|
||||
lines = [
|
||||
f"Post URL: {post_url}",
|
||||
f"Shortcode: {shortcode}",
|
||||
f"Type: {post_type}",
|
||||
]
|
||||
if post_type == "carousel":
|
||||
lines.append(f"Slide count: {len(cdn_urls)}")
|
||||
lines += [
|
||||
f"Caption: {caption}",
|
||||
f"Username: @{username}",
|
||||
f"Fetched at: {datetime.now(timezone.utc).isoformat()}",
|
||||
"CDN URLs:",
|
||||
]
|
||||
for filename, url in cdn_urls.items():
|
||||
lines.append(f" {filename:<16} {url}")
|
||||
|
||||
with open(os.path.join(post_dir, "metadata.txt"), "w", encoding="utf-8") as f:
|
||||
f.write("\n".join(lines) + "\n")
|
||||
```
|
||||
|
||||
### Step 9 — Print completion summary
|
||||
|
||||
After processing all URLs, print the summary table to the terminal (format shown in Output Structure section above). Include:
|
||||
- Total URLs attempted
|
||||
- Posts successfully saved
|
||||
- Total files written (images + PDFs separately)
|
||||
- Any URLs that were skipped and the reason
|
||||
|
||||
### Step 10 — Handle errors gracefully
|
||||
|
||||
| Error scenario | Action |
|
||||
|---|---|
|
||||
| URL is not an Instagram URL | Skip with message: "Skipped — not an Instagram URL: [url]" |
|
||||
| Post is private or requires login | Skip with message: "Skipped — post is private or login required: [url]" |
|
||||
| CDN fetch returns 403/404 | Try alternate CDN URL if available; if none, skip slide and note in metadata |
|
||||
| Pillow not installed | Skip PDF stitching, save slides only, note in summary |
|
||||
| Network timeout | Retry once after 5 seconds; if still failing, skip and log |
|
||||
| Folder name collision | Append shortcode suffix to folder name |
|
||||
| Rate limiting (429) | Wait 10 seconds and retry; log if retry also fails |
|
||||
|
||||
---
|
||||
|
||||
## Bonus — Downloading Instagram Reels (Video)
|
||||
|
||||
This skill covers images and carousel PDFs. For Reels video files, Claude Code cannot download video directly without a third-party tool, because Instagram's video CDN uses signed URLs and additional auth tokens.
|
||||
|
||||
**Recommended approach for Reels:**
|
||||
|
||||
Use `yt-dlp`, a maintained open-source tool:
|
||||
|
||||
```bash
|
||||
# Install
|
||||
pip install yt-dlp
|
||||
|
||||
# Download a Reel
|
||||
yt-dlp "https://www.instagram.com/reel/XXXX/" -o "%(title)s.%(ext)s"
|
||||
|
||||
# Download to a specific folder
|
||||
yt-dlp "https://www.instagram.com/reel/XXXX/" \
|
||||
-o "./instagram-downloads/%(uploader)s_%(id)s.%(ext)s"
|
||||
|
||||
# Download best quality
|
||||
yt-dlp -f "bestvideo+bestaudio" "https://www.instagram.com/reel/XXXX/"
|
||||
```
|
||||
|
||||
Claude can run this command via Bash if the user asks. `yt-dlp` handles the auth token extraction automatically for public Reels.
|
||||
|
||||
---
|
||||
|
||||
## Full Script Template
|
||||
|
||||
Claude should offer to write this as a standalone script (`instagram_downloader.py`) that the user can run independently:
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Instagram Post Downloader
|
||||
Fetches high-res images from public Instagram posts and carousels.
|
||||
Requires: pip install requests Pillow
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
import requests
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
PILLOW_AVAILABLE = True
|
||||
except ImportError:
|
||||
PILLOW_AVAILABLE = False
|
||||
print("Warning: Pillow not installed. PDF stitching disabled. Run: pip install Pillow")
|
||||
|
||||
|
||||
HEADERS = {
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 "
|
||||
"(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
||||
"Accept-Language": "en-US,en;q=0.9",
|
||||
"Referer": "https://www.instagram.com/",
|
||||
}
|
||||
|
||||
|
||||
def extract_shortcode(url: str) -> str:
|
||||
match = re.search(r"instagram\.com/(?:p|reel|tv)/([A-Za-z0-9_-]+)", url)
|
||||
if not match:
|
||||
raise ValueError(f"Cannot extract shortcode from URL: {url}")
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def fetch_post_data(shortcode: str) -> dict:
|
||||
"""Try multiple endpoints to get post JSON data."""
|
||||
# Attempt A: JSON endpoint
|
||||
try:
|
||||
url = f"https://www.instagram.com/p/{shortcode}/?__a=1&__d=dis"
|
||||
r = requests.get(url, headers=HEADERS, timeout=15)
|
||||
if r.status_code == 200:
|
||||
data = r.json()
|
||||
media = (data.get("graphql", {}).get("shortcode_media") or
|
||||
data.get("data", {}).get("shortcode_media"))
|
||||
if media:
|
||||
return media
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Attempt B: Embed page
|
||||
try:
|
||||
url = f"https://www.instagram.com/p/{shortcode}/embed/captioned/"
|
||||
r = requests.get(url, headers=HEADERS, timeout=15)
|
||||
html = r.text
|
||||
# Look for JSON blob in script tags
|
||||
matches = re.findall(r'window\.__additionalDataLoaded\([^,]+,(\{.+?\})\);', html)
|
||||
for blob in matches:
|
||||
try:
|
||||
data = json.loads(blob)
|
||||
media = (data.get("graphql", {}).get("shortcode_media") or
|
||||
data.get("data", {}).get("shortcode_media"))
|
||||
if media:
|
||||
return media
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return {}
|
||||
|
||||
|
||||
def get_cdn_urls(media: dict) -> list[tuple[str, str]]:
|
||||
"""Return list of (filename, cdn_url) tuples."""
|
||||
results = []
|
||||
media_type = media.get("__typename", "")
|
||||
|
||||
if media_type == "GraphSidecar":
|
||||
edges = media.get("edge_sidecar_to_children", {}).get("edges", [])
|
||||
for i, edge in enumerate(edges, start=1):
|
||||
node = edge.get("node", {})
|
||||
resources = node.get("display_resources", [])
|
||||
url = (max(resources, key=lambda r: r.get("config_width", 0)).get("src")
|
||||
if resources else node.get("display_url", ""))
|
||||
if url:
|
||||
ext = "jpg" if "jpg" in url.lower() else "webp"
|
||||
filename = f"slide_{i:02d}.{ext}"
|
||||
results.append((filename, url))
|
||||
else:
|
||||
resources = media.get("display_resources", [])
|
||||
url = (max(resources, key=lambda r: r.get("config_width", 0)).get("src")
|
||||
if resources else media.get("display_url", ""))
|
||||
if url:
|
||||
ext = "jpg" if "jpg" in url.lower() else "webp"
|
||||
results.append((f"image.{ext}", url))
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def sanitise_folder_name(caption: str, shortcode: str) -> str:
|
||||
truncated = caption[:40] if caption else ""
|
||||
cleaned = re.sub(r"[^a-zA-Z0-9 \-]", "", truncated)
|
||||
underscored = re.sub(r"[\s\-]+", "_", cleaned).strip("_").lower()
|
||||
return underscored if underscored else shortcode
|
||||
|
||||
|
||||
def download_file(url: str, dest_path: str) -> bool:
|
||||
r = requests.get(url, headers=HEADERS, stream=True, timeout=30)
|
||||
r.raise_for_status()
|
||||
with open(dest_path, "wb") as f:
|
||||
for chunk in r.iter_content(chunk_size=8192):
|
||||
f.write(chunk)
|
||||
return True
|
||||
|
||||
|
||||
def stitch_pdf(image_paths: list[str], output_path: str) -> None:
|
||||
if not PILLOW_AVAILABLE:
|
||||
return
|
||||
images = [Image.open(p).convert("RGB") for p in sorted(image_paths)]
|
||||
if images:
|
||||
images[0].save(output_path, format="PDF", save_all=True,
|
||||
append_images=images[1:], resolution=150.0)
|
||||
|
||||
|
||||
def process_url(post_url: str, base_dir: str, stitch_pdf_flag: bool) -> dict:
|
||||
result = {"url": post_url, "status": "ok", "files": [], "error": None}
|
||||
try:
|
||||
shortcode = extract_shortcode(post_url)
|
||||
media = fetch_post_data(shortcode)
|
||||
|
||||
caption = ""
|
||||
username = ""
|
||||
if media:
|
||||
caption_edges = media.get("edge_media_to_caption", {}).get("edges", [])
|
||||
caption = caption_edges[0]["node"]["text"] if caption_edges else ""
|
||||
owner = media.get("owner", {})
|
||||
username = owner.get("username", "")
|
||||
|
||||
folder_name = sanitise_folder_name(caption, shortcode)
|
||||
post_dir = os.path.join(base_dir, folder_name)
|
||||
if os.path.exists(post_dir):
|
||||
post_dir = f"{post_dir}_{shortcode}"
|
||||
os.makedirs(post_dir, exist_ok=True)
|
||||
|
||||
cdn_urls = get_cdn_urls(media) if media else []
|
||||
if not cdn_urls:
|
||||
# Fallback: oEmbed
|
||||
oembed_url = f"https://api.instagram.com/oembed/?url={post_url}&omitscript=true"
|
||||
r = requests.get(oembed_url, headers=HEADERS, timeout=10)
|
||||
if r.status_code == 200:
|
||||
thumb = r.json().get("thumbnail_url", "")
|
||||
if thumb:
|
||||
cdn_urls = [("image.jpg", thumb)]
|
||||
username = r.json().get("author_name", "")
|
||||
|
||||
downloaded_paths = []
|
||||
cdn_map = {}
|
||||
for filename, url in cdn_urls:
|
||||
dest = os.path.join(post_dir, filename)
|
||||
download_file(url, dest)
|
||||
downloaded_paths.append(dest)
|
||||
cdn_map[filename] = url
|
||||
result["files"].append(filename)
|
||||
|
||||
if stitch_pdf_flag and len(downloaded_paths) > 1 and PILLOW_AVAILABLE:
|
||||
pdf_path = os.path.join(post_dir, "carousel.pdf")
|
||||
stitch_pdf(downloaded_paths, pdf_path)
|
||||
result["files"].append("carousel.pdf")
|
||||
|
||||
post_type = "carousel" if len(cdn_urls) > 1 else "single_image"
|
||||
write_metadata(post_dir, post_url, shortcode, post_type, caption, username, cdn_map)
|
||||
result["files"].append("metadata.txt")
|
||||
|
||||
except Exception as e:
|
||||
result["status"] = "error"
|
||||
result["error"] = str(e)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def write_metadata(post_dir, post_url, shortcode, post_type, caption, username, cdn_map):
|
||||
lines = [
|
||||
f"Post URL: {post_url}",
|
||||
f"Shortcode: {shortcode}",
|
||||
f"Type: {post_type}",
|
||||
]
|
||||
if post_type == "carousel":
|
||||
lines.append(f"Slide count: {len([k for k in cdn_map if 'slide' in k])}")
|
||||
lines += [
|
||||
f"Caption: {caption}",
|
||||
f"Username: @{username}",
|
||||
f"Fetched at: {datetime.now(timezone.utc).isoformat()}",
|
||||
"CDN URLs:",
|
||||
]
|
||||
for fn, url in cdn_map.items():
|
||||
lines.append(f" {fn:<18} {url}")
|
||||
with open(os.path.join(post_dir, "metadata.txt"), "w", encoding="utf-8") as f:
|
||||
f.write("\n".join(lines) + "\n")
|
||||
|
||||
|
||||
def main(urls: list[str], base_dir: str = "./instagram-downloads", stitch: bool = True):
|
||||
os.makedirs(base_dir, exist_ok=True)
|
||||
results = []
|
||||
for url in urls:
|
||||
url = url.strip()
|
||||
if not url:
|
||||
continue
|
||||
print(f"Processing: {url}")
|
||||
r = process_url(url, base_dir, stitch)
|
||||
results.append(r)
|
||||
time.sleep(1) # polite delay between requests
|
||||
|
||||
# Summary
|
||||
ok = [r for r in results if r["status"] == "ok"]
|
||||
err = [r for r in results if r["status"] == "error"]
|
||||
total_files = sum(len(r["files"]) for r in ok)
|
||||
print("\nInstagram Post Downloader — Batch Complete")
|
||||
print("==========================================")
|
||||
print(f"URLs processed: {len(results)}")
|
||||
print(f"Posts saved: {len(ok)}")
|
||||
print(f"Total files: {total_files}")
|
||||
print(f"Errors: {len(err)}")
|
||||
print(f"Output dir: {os.path.abspath(base_dir)}\n")
|
||||
for r in results:
|
||||
if r["status"] == "ok":
|
||||
print(f" OK {r['url']}")
|
||||
else:
|
||||
print(f" ERR {r['url']} — {r['error']}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python instagram_downloader.py <url1> [url2] ...")
|
||||
sys.exit(1)
|
||||
main(sys.argv[1:])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quality Checks
|
||||
|
||||
Before marking the task complete, verify each item:
|
||||
|
||||
- [ ] Domain allowlist confirmed — `*.cdninstagram.com` is added before any fetch attempts
|
||||
- [ ] All provided URLs validated as Instagram URLs before processing begins
|
||||
- [ ] CDN URLs are the highest-resolution variants available (largest `config_width` selected)
|
||||
- [ ] Folder name is sanitised — no special characters, no spaces, max 40 chars from caption
|
||||
- [ ] Folder collision handled — shortcode appended if folder already exists
|
||||
- [ ] Carousel slides numbered sequentially with zero-padding (`slide_01`, `slide_02`, ...)
|
||||
- [ ] PDF includes all slides in correct order (not alphabetical — by slide index)
|
||||
- [ ] metadata.txt written to every post folder, including full CDN URLs
|
||||
- [ ] Pillow dependency checked at startup — graceful fallback if not available
|
||||
- [ ] Batch completion summary printed with file counts and any errors
|
||||
- [ ] Private post errors caught and reported — not silently skipped
|
||||
- [ ] Rate limiting handled — at least 1 second delay between requests
|
||||
- [ ] No credential or cookie storage — skill operates on public posts only
|
||||
|
||||
---
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "Download this Instagram post for me: https://www.instagram.com/p/ABC123/"
|
||||
- "Save that carousel to my downloads folder"
|
||||
- "Can you grab all the slides from this Instagram post and make a PDF?"
|
||||
- "Download these 5 Instagram posts" [followed by list of URLs]
|
||||
- "Archive this IG post before it gets deleted"
|
||||
- "I need the full-res images from this carousel"
|
||||
- "Download the images from this Instagram URL and stitch them into a PDF"
|
||||
- "Batch download these Instagram posts" [followed by URLs]
|
||||
- "Save the slides from this Instagram carousel as individual JPEGs"
|
||||
- "Get me the high-res version of this Instagram image"
|
||||
|
||||
---
|
||||
|
||||
## Notes on Instagram's Anti-Scraping Measures
|
||||
|
||||
Instagram actively changes its page structure and API endpoints. If all three fetch attempts fail:
|
||||
|
||||
1. The embed page method (`/embed/captioned/`) is historically the most stable — start there.
|
||||
2. CDN URLs expire. Download immediately after fetching — do not store URLs and download later.
|
||||
3. Instagram may return a login wall for some posts even if they're technically public. If this happens, the skill cannot proceed without authentication (which is out of scope).
|
||||
4. If Instagram returns a 429, wait 10–30 seconds before retrying. Reduce batch size for large lists.
|
||||
|
||||
This skill is designed for public posts only. It does not support login, sessions, or private content.
|
||||
|
||||
---
|
||||
|
||||
*Originally inspired by a skill from Frank and Diana Dovgopol (Write, Prompt, Scale) — adapted and extended for this library.*
|
||||
@@ -0,0 +1,166 @@
|
||||
---
|
||||
name: notes-humanizer
|
||||
description: Strips AI writing patterns from text and rewrites it to sound genuinely human — not by softening it, but by removing statistical defaults and injecting the specific signals that human writers produce.
|
||||
---
|
||||
|
||||
# Notes Humanizer
|
||||
|
||||
"Humanize this" prompts don't work because they don't know what to remove. AI text has specific, identifiable defaults — em dashes used as parenthetical substitutes, rule-of-three lists where all items have identical rhythm, sentences that hover between 15 and 20 words. Fix those defaults, add the signals human writers actually produce, and the text stops reading as synthetic. This skill does that systematically, in two phases, and shows you exactly what changed and why.
|
||||
|
||||
> Credit: Originally created by Orel (TheIndiepreneur) — adapted and extended for this library.
|
||||
|
||||
---
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Format | Notes |
|
||||
|---|---|---|
|
||||
| Text to humanize | Paste directly into the chat | Any length. Works on paragraphs, full articles, social posts, emails. |
|
||||
|
||||
No other inputs required. Claude will not ask clarifying questions before starting — it works with what's given.
|
||||
|
||||
---
|
||||
|
||||
## Output Structure
|
||||
|
||||
### Section 1: What Was Found
|
||||
|
||||
A plain-language audit of the AI patterns detected in the original text, before any rewriting:
|
||||
|
||||
```
|
||||
PATTERNS DETECTED
|
||||
─────────────────
|
||||
Em dashes used as parenthetical substitutes: 3
|
||||
Filler openers ("Let's dive in", "It's worth noting", etc.): 2
|
||||
Rule-of-three lists with identical rhythm: 1
|
||||
Sentence length variance: low (avg 17 words, range 14–21)
|
||||
Hedging qualifiers: 4
|
||||
Passive constructions where active is cleaner: 2
|
||||
```
|
||||
|
||||
### Section 2: Side-by-Side Comparison
|
||||
|
||||
| Original | Rewritten |
|
||||
|---|---|
|
||||
| [original paragraph] | [rewritten paragraph] |
|
||||
|
||||
(One row per paragraph or logical block. Short texts get the full comparison in one table. Long texts get the table collapsed to changed sections only, with unchanged sections noted.)
|
||||
|
||||
### Section 3: Change Log
|
||||
|
||||
Every specific change made, with the reason:
|
||||
|
||||
```
|
||||
CHANGES MADE
|
||||
────────────────────────────────────────────────
|
||||
1. Removed em dash in "success — and it shows"
|
||||
→ Rewritten as "success (and it shows)"
|
||||
Why: em dash here is a parenthetical substitute, not a genuine pause
|
||||
|
||||
2. Deleted "It's worth noting that"
|
||||
Why: pure filler — the sentence is stronger without it
|
||||
|
||||
3. Broke rule-of-three list "X, Y, and Z"
|
||||
→ "X and Y. Z is different — [expanded thought]"
|
||||
Why: all three items had identical rhythm; broke the pattern
|
||||
|
||||
4. Added short sentence: "That's the problem."
|
||||
Why: needed a sub-8-word sentence to vary rhythm
|
||||
|
||||
5. Added sentence starting with "But"
|
||||
Why: human writers do this; AI avoids it as a statistical default
|
||||
|
||||
6. Added specific example: [detail added]
|
||||
Why: the original made an abstract claim with no grounding detail
|
||||
|
||||
7. Added aside: "(I've watched this fail three times in a row)"
|
||||
Why: breaks fourth wall slightly; signals genuine perspective
|
||||
```
|
||||
|
||||
### Section 4: Clean Output
|
||||
|
||||
The full rewritten text, ready to copy and paste — no annotations, no formatting artifacts.
|
||||
|
||||
```
|
||||
[Full rewritten text here]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Instructions for Claude
|
||||
|
||||
### Phase 1: Audit
|
||||
|
||||
Read the full text before making any changes. Identify and count every instance of these patterns:
|
||||
|
||||
**Patterns to remove or rewrite:**
|
||||
|
||||
| Pattern | Action |
|
||||
|---|---|
|
||||
| Em dash used as parenthetical substitute (`word — word` where a comma or parenthesis would work) | Replace with parentheses or rewrite the clause |
|
||||
| "Let's dive in" | Delete or replace with a direct first sentence |
|
||||
| "In conclusion" | Delete or rewrite as a genuine closing thought |
|
||||
| "It's worth noting that" | Delete — the sentence stands without it |
|
||||
| "At its core" | Delete or rewrite |
|
||||
| "Game-changer" | Replace with what the thing actually changes |
|
||||
| "Delve" | Replace with look, dig, explore — or rewrite the sentence |
|
||||
| "Navigate" used metaphorically for non-navigation tasks | Replace with a direct verb |
|
||||
| Rule-of-three lists where all three items have identical grammatical structure and similar word count | Break the third item out as its own sentence or expand it |
|
||||
| Sentences where every sentence in a paragraph falls in the 14–22 word range | Deliberately add one very short sentence and one longer one |
|
||||
| "Needless to say" | Delete |
|
||||
| "It's important to note that" | Delete |
|
||||
| Passive constructions where the active form is more direct | Flip to active |
|
||||
|
||||
Do not remove every em dash — only the ones used as parenthetical substitutes. Do not remove all hedging — only empty hedging that adds no information.
|
||||
|
||||
### Phase 2: Inject
|
||||
|
||||
After stripping patterns, add the following signals. Each one should emerge from the actual content — don't add generic filler:
|
||||
|
||||
1. **One genuine opinion or take.** The author appears to actually believe something specific. State it without hedging. ("This approach works, and I think most people underestimate how rarely the alternative does.")
|
||||
|
||||
2. **One specific detail, example, or number.** Ground the most abstract claim in the text with something concrete. If the text says "this happens frequently," add a real or illustrative number. If it says "many companies do this," name the type of company.
|
||||
|
||||
3. **One aside or parenthetical thought that breaks the fourth wall slightly.** This is the signal most synthetic text lacks — the writer momentarily steps out of the formal argument to say something human. ("(I've seen this specific mistake made by people who absolutely should have known better.)")
|
||||
|
||||
4. **At least one sentence under 8 words.** Make it land on a point, not a transition.
|
||||
|
||||
5. **One sentence that starts with "And" or "But."** Place it where the rhythm earns it, not randomly.
|
||||
|
||||
### Phase 3: Report
|
||||
|
||||
Present the output in the four-section structure defined above. The change log must list every individual change — not categories of change, but specific instances. If you changed three em dashes, list all three separately.
|
||||
|
||||
### Handling edge cases
|
||||
|
||||
- **If the text is already mostly clean:** Report what you found (or didn't find), make the few remaining changes, and note explicitly that the original was close. Don't invent problems.
|
||||
- **If the text is very short (under 100 words):** Skip the comparison table. Show original, then rewritten, then change log.
|
||||
- **If the text is over 1,500 words:** Process the full text but collapse the comparison table to changed sections only.
|
||||
|
||||
---
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] Audit was completed before rewriting (patterns counted, not just detected)
|
||||
- [ ] Every removed pattern is listed in the change log with a specific reason
|
||||
- [ ] Em dashes were assessed individually — only parenthetical-substitute uses were removed
|
||||
- [ ] Rule-of-three lists: the rhythm was actually checked, not just the fact that there were three items
|
||||
- [ ] At least one sentence under 8 words was added (or was already present)
|
||||
- [ ] At least one sentence starts with "And" or "But" in the final text
|
||||
- [ ] The specific detail or example added connects to an actual claim in the text, not floated in generically
|
||||
- [ ] The aside breaks the fourth wall slightly without being forced or cutesy
|
||||
- [ ] The change log lists specific instances, not categories
|
||||
- [ ] The clean output section has no annotations or formatting artifacts — ready to paste
|
||||
- [ ] If the original was already clean, that was stated explicitly rather than changes invented
|
||||
|
||||
---
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "Humanize this text: [paste]"
|
||||
- "Use the notes-humanizer skill on this draft"
|
||||
- "This reads like ChatGPT wrote it — fix it: [paste]"
|
||||
- "Strip the AI out of this and make it sound like a real person wrote it"
|
||||
- "Run the humanizer on this LinkedIn post: [paste]"
|
||||
- "This has too many em dashes and rule-of-three lists — clean it up: [paste]"
|
||||
- "Make this email sound less robotic: [paste]"
|
||||
@@ -0,0 +1,176 @@
|
||||
---
|
||||
name: substack-notes-scraper
|
||||
description: Scrapes a Substack Notes page and exports engagement data (likes, comments, restacks) to a formatted .xlsx file with conditional formatting and summary stats.
|
||||
---
|
||||
|
||||
# Substack Notes Scraper
|
||||
|
||||
Substack has no public API for Notes analytics. You can't see likes, comments, and restacks in one place without scrolling through your feed manually. This skill scrapes the rendered Notes page, filters to only your original content, and exports everything to a spreadsheet you can actually analyze.
|
||||
|
||||
> Credit: Originally created by a Substack newsletter author — adapted and extended for this library.
|
||||
|
||||
---
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Format | Example |
|
||||
|---|---|---|
|
||||
| Notes URL | Full URL to the Notes tab | `https://substack.com/@handle/notes` |
|
||||
| Author handle or name | Exact handle or display name | `@handle` or `Jane Smith` |
|
||||
| Date range | Plain English or explicit range | `last 30 days` or `Jan 2026 – Mar 2026` |
|
||||
|
||||
Claude will ask for these if not provided upfront.
|
||||
|
||||
---
|
||||
|
||||
## Output Structure
|
||||
|
||||
### File
|
||||
|
||||
```
|
||||
substack-notes-[handle]-[YYYY-MM-DD].xlsx
|
||||
```
|
||||
|
||||
### Sheet: "Notes Data"
|
||||
|
||||
| Column | Description |
|
||||
|---|---|
|
||||
| Date | Publication date (YYYY-MM-DD) |
|
||||
| Text Preview | First 200 characters of the note |
|
||||
| Full Text | Complete note text |
|
||||
| Likes | Like count at time of scrape |
|
||||
| Comments | Comment count |
|
||||
| Restacks | Restack count |
|
||||
| Total Engagement | Likes + Comments + Restacks |
|
||||
| Link | Direct URL to the note |
|
||||
| Note Type | `original` or `restack` |
|
||||
|
||||
**Formatting applied:**
|
||||
- Row 1: frozen header row
|
||||
- Auto-filter enabled on all columns
|
||||
- Top 20% by Likes column: highlighted yellow (`#FFF2CC`)
|
||||
- Column widths: auto-fit to content, min 12, max 60
|
||||
|
||||
### Sheet: "Summary"
|
||||
|
||||
```
|
||||
Scrape Date: [YYYY-MM-DD HH:MM UTC]
|
||||
Author: [handle]
|
||||
Date Range: [start] – [end]
|
||||
Total Notes: [n]
|
||||
Original Notes: [n]
|
||||
Restacks Filtered: [n]
|
||||
|
||||
Avg Likes: [n.n]
|
||||
Avg Comments: [n.n]
|
||||
Avg Restacks: [n.n]
|
||||
Avg Total Eng: [n.n]
|
||||
|
||||
Best Note (Likes): [date] — [first 80 chars] — [n] likes
|
||||
Best Note (Eng): [date] — [first 80 chars] — [n] total engagement
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Instructions for Claude
|
||||
|
||||
### Step 1: Validate inputs
|
||||
|
||||
Confirm the three required inputs are present. If any are missing, ask before proceeding. Parse the date range into a concrete start date and end date (convert relative ranges like "last 30 days" to explicit dates using today's date).
|
||||
|
||||
### Step 2: Fetch the Notes page
|
||||
|
||||
Use `WebFetch` to load the Notes URL. Substack Notes pages are JavaScript-rendered — request the full rendered HTML. If WebFetch returns a skeleton page without note content, note this in your response and ask the user to paste the page HTML manually or confirm browser access is available.
|
||||
|
||||
### Step 3: Paginate through all notes in the date window
|
||||
|
||||
Substack Notes load incrementally. Repeat fetching or scrolling until either:
|
||||
- A note's date falls outside the target date range (stop loading more), or
|
||||
- No new content loads on the next request.
|
||||
|
||||
Rate-limit: wait 2 seconds between each paginated request. Do not hammer the endpoint.
|
||||
|
||||
### Step 4: Parse each note
|
||||
|
||||
For every note element found on the page, extract:
|
||||
- **Date**: the timestamp on the note (convert to YYYY-MM-DD)
|
||||
- **Author**: the display name or handle shown on the note
|
||||
- **Full text**: complete body text, stripping HTML tags
|
||||
- **Text preview**: first 200 characters of full text
|
||||
- **Likes count**: the number shown on the like/heart counter
|
||||
- **Comments count**: the number shown on the comment counter
|
||||
- **Restacks count**: the number shown on the restack counter
|
||||
- **Link**: the direct permalink to the note
|
||||
- **Note type**: `original` if the author matches the specified author; `restack` if it belongs to someone else
|
||||
|
||||
### Step 5: Filter
|
||||
|
||||
Keep ALL rows in the data (restacks included as rows with `Note Type = restack`). The Summary sheet stats should count only `original` notes. Mark restacks clearly so the user can filter them out themselves in Excel if preferred.
|
||||
|
||||
Apply date filter: exclude any note outside the specified date range.
|
||||
|
||||
### Step 6: Calculate Total Engagement
|
||||
|
||||
For each row: `Total Engagement = Likes + Comments + Restacks`
|
||||
|
||||
### Step 7: Identify top 20% by Likes
|
||||
|
||||
Sort original notes by Likes descending. Mark the top 20% (round up) for conditional formatting. These rows will be highlighted yellow in the output file.
|
||||
|
||||
### Step 8: Build the .xlsx file
|
||||
|
||||
Use Python with `openpyxl` to generate the file. Structure:
|
||||
|
||||
```python
|
||||
# Required libraries
|
||||
import openpyxl
|
||||
from openpyxl.styles import PatternFill, Font, Alignment
|
||||
from openpyxl.utils import get_column_letter
|
||||
from datetime import datetime
|
||||
|
||||
# Sheet 1: Notes Data
|
||||
# - Write header row, bold, freeze row 1
|
||||
# - Write all data rows
|
||||
# - Apply auto-filter: ws.auto_filter.ref = ws.dimensions
|
||||
# - Apply yellow fill to top-20% rows by likes
|
||||
# - Auto-size columns (iterate cells to find max length)
|
||||
|
||||
# Sheet 2: Summary
|
||||
# - Write summary stats as key-value pairs, no table format
|
||||
```
|
||||
|
||||
Name the file `substack-notes-[handle]-[YYYY-MM-DD].xlsx` using today's date.
|
||||
|
||||
### Step 9: Report back
|
||||
|
||||
After generating the file, report:
|
||||
- File path
|
||||
- Total notes found, original vs. restacks
|
||||
- Date range actually covered
|
||||
- Top 3 notes by total engagement (date + preview + stats)
|
||||
- Any notes or warnings (e.g., page didn't fully load, some dates were ambiguous)
|
||||
|
||||
---
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] All three required inputs were confirmed before starting
|
||||
- [ ] Rate limiting honored: 2-second delay between paginated requests
|
||||
- [ ] Author filter applied correctly — restacks are included as rows but flagged, not silently dropped
|
||||
- [ ] Date range filter applied — no notes outside the window appear in the data
|
||||
- [ ] Total Engagement column is Likes + Comments + Restacks (not hardcoded)
|
||||
- [ ] Top 20% highlight is based on the actual data distribution, not a fixed threshold
|
||||
- [ ] Header row is frozen and auto-filter is active
|
||||
- [ ] Summary sheet stats reference only `original` notes, not restacks
|
||||
- [ ] File is named with the author handle and today's date
|
||||
- [ ] If the page failed to load properly, the user was told — not silently given an empty file
|
||||
|
||||
---
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "Scrape my Substack Notes and export to Excel — my handle is @handle, last 60 days"
|
||||
- "Use the substack-notes-scraper skill on https://substack.com/@handle/notes for Q1 2026"
|
||||
- "Pull my notes engagement data into a spreadsheet"
|
||||
- "Export my Substack Notes stats with likes and restacks — author: Jane Smith, Jan–Mar 2026"
|
||||
- "Run the Substack scraper on my notes page and show me which posts performed best"
|
||||
@@ -0,0 +1,625 @@
|
||||
---
|
||||
name: thumbnail-creator
|
||||
description: "Generate article or newsletter thumbnail candidates using the Gemini API from inside Claude Code. Claude reads article copy, proposes composition concepts, writes image generation prompts incorporating brand specs, calls Gemini to generate the images, evaluates the results via computer vision, and returns ranked candidates with rationale. Use when asked to create thumbnails, generate cover images, or produce visual candidates for an article or newsletter."
|
||||
---
|
||||
|
||||
# Thumbnail Creator Skill (via Gemini)
|
||||
|
||||
Generates article and newsletter thumbnail candidates by acting as an image-generation agent inside Claude Code. Instead of switching between tools and prompting Gemini's web UI one image at a time, this skill makes Claude do the full loop: read the copy, propose compositions, write tailored prompts, call the Gemini API, evaluate the outputs, and return ranked results with brief rationale.
|
||||
|
||||
The output is production-ready thumbnail candidates you can drop directly into your CMS, newsletter tool, or social scheduler.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Both of these must be in place before the skill can generate images:
|
||||
|
||||
### 1. Gemini API Key
|
||||
|
||||
Get a free key from [Google AI Studio](https://aistudio.google.com/app/apikey).
|
||||
|
||||
Set it as an environment variable:
|
||||
|
||||
```bash
|
||||
export GEMINI_API_KEY="your-key-here"
|
||||
```
|
||||
|
||||
To persist it across sessions, add to your shell profile (`~/.zshrc` or `~/.bashrc`):
|
||||
|
||||
```bash
|
||||
echo 'export GEMINI_API_KEY="your-key-here"' >> ~/.zshrc
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
Verify it is set:
|
||||
|
||||
```bash
|
||||
echo $GEMINI_API_KEY
|
||||
```
|
||||
|
||||
### 2. generate_image.py Script
|
||||
|
||||
This script must exist at `./generate_image.py` in the project root. The full template is provided in the Script Template section below. Claude will check for it and offer to create it if missing.
|
||||
|
||||
**Python dependencies:**
|
||||
|
||||
```bash
|
||||
pip install google-generativeai Pillow requests
|
||||
```
|
||||
|
||||
Or with uv:
|
||||
|
||||
```bash
|
||||
uv pip install google-generativeai Pillow requests
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Required Inputs
|
||||
|
||||
Claude will ask for these if not provided:
|
||||
|
||||
| Input | Required | Notes |
|
||||
|---|---|---|
|
||||
| Article copy or URL | Yes | Paste the full article text, or provide a URL to fetch. Used to extract themes, hooks, and key claims for composition. |
|
||||
| Brand colours | Recommended | Hex codes or descriptive names. E.g. `#1A1A2E` (navy), `#E94560` (coral). If not provided, Claude uses clean neutral defaults. |
|
||||
| Fonts / type style | Recommended | E.g. "bold sans-serif", "editorial serif", "Neue Haas Grotesk". Used in prompt to guide text treatment. |
|
||||
| Style reference description | Recommended | E.g. "flat illustration, minimal, like Stripe's marketing site" or "photorealistic, dark background, high contrast". A style image URL can also be provided. |
|
||||
| Output dimensions | No | Defaults to `1792x1024` (landscape, standard article thumbnail). Options: `1024x1024` (square), `1024x1792` (portrait/mobile). |
|
||||
| Number of candidates | No | Defaults to 4. Min 1, max 8 (API limits and cost). |
|
||||
| Article title (if different from H1) | No | Used as the primary text element in image prompts. |
|
||||
| Candidate selection | No | After proposing compositions, Claude asks which to generate. User can say "all" or pick by number. |
|
||||
|
||||
---
|
||||
|
||||
## Output Structure
|
||||
|
||||
### Phase 1 — Composition Proposals (text, before any API calls)
|
||||
|
||||
Claude presents 3-4 composition concepts for user approval. Format:
|
||||
|
||||
```
|
||||
Composition Concepts for: "[Article Title]"
|
||||
|
||||
1. BOLD CLAIM
|
||||
Layout: Full-bleed dark background, large white headline centred,
|
||||
single accent data point (e.g. "3x faster") in brand colour below
|
||||
Mood: High authority, newsletter-style
|
||||
Best for: LinkedIn, Substack headers
|
||||
Rationale: The article's central claim ("X outperforms Y by 3x") is specific
|
||||
enough to anchor the visual — readers stop on data.
|
||||
|
||||
2. CONCEPTUAL OBJECT
|
||||
Layout: Central object illustration (e.g. a broken clock for a time-waste article),
|
||||
title in upper third, minimal texture background
|
||||
Mood: Editorial, Medium-style
|
||||
Best for: Blog header, Medium cover, email preheader
|
||||
Rationale: Gives art directors visual metaphor flexibility; works across sizes.
|
||||
|
||||
3. CONTRAST SPLIT
|
||||
Layout: Left half brand colour, right half white or image,
|
||||
title on colour side, supporting subtext on white side
|
||||
Mood: Clean, professional, startup-brand feel
|
||||
Best for: Newsletter, LinkedIn carousel first slide
|
||||
Rationale: Split layout performs consistently in newsletter A/B tests;
|
||||
text is readable at small sizes.
|
||||
|
||||
4. TYPOGRAPHIC ONLY
|
||||
Layout: No illustration, oversized title treatment,
|
||||
author name in small caps at bottom, thin rule separator
|
||||
Mood: Premium, confident, editorial
|
||||
Best for: Substack, Ghost, high-density email lists
|
||||
Rationale: Works when the brand has strong type identity. Fastest to produce.
|
||||
|
||||
Which compositions do you want generated? (Reply with numbers, e.g. "1, 3" or "all")
|
||||
```
|
||||
|
||||
### Phase 2 — Generated Image Files
|
||||
|
||||
After generation, Claude saves files to `./thumbnails/[article-slug]/`:
|
||||
|
||||
```
|
||||
thumbnails/
|
||||
└── article-slug-from-title/
|
||||
├── candidate_01_bold_claim.png
|
||||
├── candidate_02_conceptual_object.png
|
||||
├── candidate_03_contrast_split.png
|
||||
├── candidate_04_typographic.png
|
||||
└── evaluation_report.md
|
||||
```
|
||||
|
||||
### Phase 3 — Evaluation Summary Table
|
||||
|
||||
Claude evaluates each returned image via computer vision and produces:
|
||||
|
||||
```
|
||||
Thumbnail Evaluation — "[Article Title]"
|
||||
Generated: 2026-05-27 | Model: Gemini Imagen | Dimensions: 1792x1024
|
||||
|
||||
| # | Candidate | Composition | Brand Fit /10 | Text Legibility /10 | Recommendation |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | candidate_01_bold_claim.png | Bold Claim | 9 | 8 | ★ Top pick — strong data anchor, brand colours correct, title readable at 200px width |
|
||||
| 2 | candidate_02_conceptual_object.png | Conceptual Object | 7 | 9 | Good fallback — legible, clean, but illustration style drifted slightly from brand |
|
||||
| 3 | candidate_03_contrast_split.png | Contrast Split | 8 | 7 | Works well at full size; test at thumbnail size before publishing — right side text tightens |
|
||||
| 4 | candidate_04_typographic.png | Typographic | 9 | 10 | Strongest for email — zero brand drift risk, completely text-based |
|
||||
|
||||
Recommended for web: candidate_01_bold_claim.png
|
||||
Recommended for email/mobile: candidate_04_typographic.png
|
||||
Recommended for social: candidate_03_contrast_split.png
|
||||
|
||||
Files saved to: ./thumbnails/article-slug-from-title/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## How Claude Should Execute This Skill
|
||||
|
||||
### Step 1 — Ingest and analyse the article
|
||||
|
||||
Accept article copy as pasted text or a URL.
|
||||
|
||||
If a URL is provided, fetch the page and extract:
|
||||
- The H1 title
|
||||
- The first 3-5 paragraphs (the hook, central claim, and key points)
|
||||
- Any notable statistics or named frameworks mentioned
|
||||
- The author name (for typographic compositions)
|
||||
|
||||
If text is pasted, read it directly. Focus on:
|
||||
- **The hook:** What is the opening claim or tension?
|
||||
- **The central thesis:** What is the one thing the article argues or teaches?
|
||||
- **Key specifics:** Any numbers, named frameworks, or concrete examples that could anchor a visual
|
||||
- **Tone:** Is this formal/authoritative, conversational/accessible, provocative/challenge-based?
|
||||
|
||||
Summarise these findings internally before proposing compositions — the proposals should feel tailored to this specific article, not generic.
|
||||
|
||||
### Step 2 — Collect brand specs
|
||||
|
||||
Ask the user for brand specs if not provided:
|
||||
|
||||
```
|
||||
To generate on-brand thumbnails, I need a few details:
|
||||
|
||||
1. Brand colours (hex codes or descriptions) — e.g. #1A1A2E, #E94560
|
||||
2. Font style preference — e.g. "bold sans-serif", "editorial serif", "geometric"
|
||||
3. Visual style — e.g. "flat minimal", "photorealistic", "illustrated", "typographic only"
|
||||
4. Any style references — describe a brand or publication whose aesthetic you want to match,
|
||||
or share an image URL
|
||||
|
||||
If you don't have brand specs yet, say "use clean defaults" and I'll use a professional
|
||||
dark-on-white editorial style.
|
||||
```
|
||||
|
||||
If the user says "use clean defaults", apply:
|
||||
- Background: `#FFFFFF` or `#0F0F0F` (dark mode default)
|
||||
- Accent: `#2563EB` (blue)
|
||||
- Font style: bold geometric sans-serif
|
||||
- Style: minimal flat, no textures, high contrast
|
||||
|
||||
### Step 3 — Propose composition concepts
|
||||
|
||||
Write 3-4 composition concepts tailored to the article's tone and content. Each concept must:
|
||||
- Have a name (short, memorable label)
|
||||
- Describe the layout precisely (where title goes, what visual element anchors it, background treatment)
|
||||
- Note the mood and the use case it's best suited for
|
||||
- Include a rationale sentence explaining why this composition fits this specific article
|
||||
|
||||
After presenting the concepts, ask which to generate. Wait for user confirmation before making any API calls.
|
||||
|
||||
### Step 4 — Write Gemini image generation prompts
|
||||
|
||||
For each selected composition, write a detailed image generation prompt. Image generation prompts follow a different grammar than text prompts — they are descriptive, not instructional.
|
||||
|
||||
**Prompt structure:**
|
||||
```
|
||||
[Subject/composition] + [Style] + [Colour palette] + [Mood/lighting] +
|
||||
[Text treatment if any] + [What to avoid]
|
||||
```
|
||||
|
||||
**Example prompt for Bold Claim composition:**
|
||||
```
|
||||
Article thumbnail image. Large bold white sans-serif headline text reading "3x Faster Than
|
||||
Traditional Methods" centred on a deep navy blue background (#1A1A2E). Small coral accent
|
||||
text (#E94560) below reading the subtitle. Minimal flat design, no gradients, no stock photo
|
||||
elements, no people. Clean professional editorial style, high contrast, newsletter header
|
||||
format, 16:9 landscape orientation. The composition is typographic — text is the hero,
|
||||
no illustration required. Avoid: clip art, drop shadows, low contrast, crowded layout.
|
||||
```
|
||||
|
||||
**Prompt rules:**
|
||||
- Include exact hex colours when brand colours are provided
|
||||
- Specify the exact headline text to appear in the image
|
||||
- Name the style explicitly ("flat design", "editorial", "photorealistic") — Gemini responds well to style category names
|
||||
- Add a negative prompt ("Avoid: ...") at the end to reduce drift from brand style
|
||||
- Keep prompts under 300 words — longer prompts do not reliably produce better outputs
|
||||
|
||||
### Step 5 — Check prerequisites and run the generation script
|
||||
|
||||
Before calling the API, verify:
|
||||
|
||||
```bash
|
||||
# Check API key is set
|
||||
echo $GEMINI_API_KEY
|
||||
|
||||
# Check script exists
|
||||
ls -la ./generate_image.py
|
||||
|
||||
# Check dependencies
|
||||
python3 -c "import google.generativeai, PIL, requests; print('Dependencies OK')"
|
||||
```
|
||||
|
||||
If the script is missing, offer to create it using the template in the Script Template section below.
|
||||
|
||||
Run the generation script for each prompt:
|
||||
|
||||
```bash
|
||||
python3 generate_image.py \
|
||||
--prompt "your full prompt here" \
|
||||
--output "./thumbnails/article-slug/candidate_01_bold_claim.png" \
|
||||
--width 1792 \
|
||||
--height 1024
|
||||
```
|
||||
|
||||
Or pass all prompts in a batch config file:
|
||||
|
||||
```bash
|
||||
python3 generate_image.py --config ./thumbnails/article-slug/prompts.json
|
||||
```
|
||||
|
||||
### Step 6 — Evaluate generated images
|
||||
|
||||
After each image is saved, examine it using computer vision. Evaluate on two dimensions:
|
||||
|
||||
**Brand Fit (score /10):**
|
||||
- Are the brand colours correct? (1-2 points each)
|
||||
- Does the style match the requested aesthetic? (2 points)
|
||||
- Is the layout consistent with the composition brief? (2 points)
|
||||
- Are there any AI artefacts, distorted text, or unintended elements? (-1 per issue)
|
||||
|
||||
**Text Legibility (score /10):**
|
||||
- Is the headline text readable at full resolution? (3 points)
|
||||
- Is the headline text readable when the image is scaled to 300px wide (thumbnail size)? (3 points)
|
||||
- Is there sufficient contrast between text and background? (2 points)
|
||||
- Is the text placement within safe zones (not cut off at edges)? (2 points)
|
||||
|
||||
Note: Gemini Imagen sometimes renders text with spelling errors or distorted letterforms. If this happens, note it in the evaluation and suggest the user add the text overlay manually in Canva or Figma.
|
||||
|
||||
### Step 7 — Produce the evaluation report
|
||||
|
||||
Write the evaluation summary table (format shown in Output Structure section) and save it as `evaluation_report.md` in the output folder.
|
||||
|
||||
Include:
|
||||
- One-line rationale for each score
|
||||
- A top pick recommendation per use case (web, email/mobile, social)
|
||||
- Any production notes (e.g. "text rendering is imperfect on candidate_02 — overlay text manually")
|
||||
- The full prompts used, so the user can iterate directly in AI Studio if needed
|
||||
|
||||
### Step 8 — Offer iteration
|
||||
|
||||
After delivering the candidates, offer one iteration pass:
|
||||
|
||||
```
|
||||
Want me to iterate on any of these?
|
||||
|
||||
Options:
|
||||
- Adjust colours or style on a specific candidate
|
||||
- Try a different composition concept
|
||||
- Change the headline text
|
||||
- Rerun with different Gemini parameters (different temperature/seed)
|
||||
- Generate additional variants of the top pick
|
||||
|
||||
Just tell me what to change.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Script Template
|
||||
|
||||
Claude should offer to write this file if `generate_image.py` is not present. This is the canonical template to use.
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
generate_image.py — Gemini Imagen wrapper for Thumbnail Creator skill.
|
||||
|
||||
Usage:
|
||||
python3 generate_image.py --prompt "..." --output "./out.png" [--width 1792] [--height 1024]
|
||||
python3 generate_image.py --config ./prompts.json
|
||||
|
||||
Config JSON format:
|
||||
[
|
||||
{
|
||||
"prompt": "...",
|
||||
"output": "./thumbnails/slug/candidate_01.png",
|
||||
"width": 1792,
|
||||
"height": 1024
|
||||
}
|
||||
]
|
||||
|
||||
Requirements:
|
||||
pip install google-generativeai Pillow
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import argparse
|
||||
import base64
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import google.generativeai as genai
|
||||
from google.generativeai import types as genai_types
|
||||
except ImportError:
|
||||
print("ERROR: google-generativeai not installed. Run: pip install google-generativeai")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
import io
|
||||
except ImportError:
|
||||
print("ERROR: Pillow not installed. Run: pip install Pillow")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def get_api_key() -> str:
|
||||
key = os.environ.get("GEMINI_API_KEY", "")
|
||||
if not key:
|
||||
print("ERROR: GEMINI_API_KEY environment variable is not set.")
|
||||
print("Get a key at: https://aistudio.google.com/app/apikey")
|
||||
print("Then run: export GEMINI_API_KEY='your-key-here'")
|
||||
sys.exit(1)
|
||||
return key
|
||||
|
||||
|
||||
def generate_image(
|
||||
prompt: str,
|
||||
output_path: str,
|
||||
width: int = 1792,
|
||||
height: int = 1024,
|
||||
) -> bool:
|
||||
"""
|
||||
Call Gemini Imagen to generate a single image and save it to output_path.
|
||||
Returns True on success, False on failure.
|
||||
"""
|
||||
api_key = get_api_key()
|
||||
genai.configure(api_key=api_key)
|
||||
|
||||
# Determine aspect ratio from dimensions
|
||||
ratio = width / height
|
||||
if abs(ratio - 16/9) < 0.1:
|
||||
aspect_ratio = "16:9"
|
||||
elif abs(ratio - 1.0) < 0.1:
|
||||
aspect_ratio = "1:1"
|
||||
elif abs(ratio - 9/16) < 0.1:
|
||||
aspect_ratio = "9:16"
|
||||
else:
|
||||
aspect_ratio = "16:9" # default fallback
|
||||
|
||||
try:
|
||||
imagen_model = genai.ImageGenerationModel("imagen-3.0-generate-002")
|
||||
|
||||
result = imagen_model.generate_images(
|
||||
prompt=prompt,
|
||||
number_of_images=1,
|
||||
aspect_ratio=aspect_ratio,
|
||||
safety_filter_level="block_only_high",
|
||||
person_generation="allow_adult",
|
||||
)
|
||||
|
||||
if not result.images:
|
||||
print(f" No images returned for: {output_path}")
|
||||
return False
|
||||
|
||||
image_data = result.images[0]
|
||||
|
||||
# Ensure output directory exists
|
||||
Path(output_path).parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Save the image
|
||||
if hasattr(image_data, '_image_bytes'):
|
||||
img_bytes = image_data._image_bytes
|
||||
elif hasattr(image_data, 'image'):
|
||||
img_bytes = image_data.image
|
||||
else:
|
||||
# Fallback: try to access raw data
|
||||
img_bytes = bytes(image_data)
|
||||
|
||||
img = Image.open(io.BytesIO(img_bytes))
|
||||
|
||||
# Resize to exact dimensions if needed
|
||||
if img.size != (width, height):
|
||||
img = img.resize((width, height), Image.LANCZOS)
|
||||
|
||||
img.save(output_path, format="PNG", optimize=True)
|
||||
print(f" Saved: {output_path} ({img.size[0]}x{img.size[1]})")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f" ERROR generating image: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def run_from_args():
|
||||
parser = argparse.ArgumentParser(description="Gemini Imagen wrapper for thumbnail generation")
|
||||
parser.add_argument("--prompt", type=str, help="Image generation prompt")
|
||||
parser.add_argument("--output", type=str, help="Output file path (.png)")
|
||||
parser.add_argument("--width", type=int, default=1792, help="Image width in pixels")
|
||||
parser.add_argument("--height", type=int, default=1024, help="Image height in pixels")
|
||||
parser.add_argument("--config", type=str, help="JSON config file with batch of prompts")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.config:
|
||||
# Batch mode
|
||||
with open(args.config, "r") as f:
|
||||
items = json.load(f)
|
||||
print(f"Batch mode: {len(items)} image(s) to generate")
|
||||
results = []
|
||||
for i, item in enumerate(items, start=1):
|
||||
print(f"\n[{i}/{len(items)}] Generating: {item['output']}")
|
||||
ok = generate_image(
|
||||
prompt=item["prompt"],
|
||||
output_path=item["output"],
|
||||
width=item.get("width", 1792),
|
||||
height=item.get("height", 1024),
|
||||
)
|
||||
results.append({"output": item["output"], "ok": ok})
|
||||
|
||||
print(f"\nBatch complete: {sum(r['ok'] for r in results)}/{len(results)} succeeded")
|
||||
for r in results:
|
||||
status = "OK " if r["ok"] else "ERR"
|
||||
print(f" {status} {r['output']}")
|
||||
|
||||
elif args.prompt and args.output:
|
||||
# Single image mode
|
||||
print(f"Generating: {args.output}")
|
||||
ok = generate_image(
|
||||
prompt=args.prompt,
|
||||
output_path=args.output,
|
||||
width=args.width,
|
||||
height=args.height,
|
||||
)
|
||||
if ok:
|
||||
print("Done.")
|
||||
else:
|
||||
print("Failed.")
|
||||
sys.exit(1)
|
||||
|
||||
else:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_from_args()
|
||||
```
|
||||
|
||||
**To create this file from inside Claude Code:**
|
||||
```bash
|
||||
# Claude will write this file if it doesn't exist:
|
||||
ls ./generate_image.py || echo "Script missing — Claude will create it"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Prompt Writing Reference
|
||||
|
||||
Claude should use this reference when writing image generation prompts. These patterns produce the most consistent results with Gemini Imagen.
|
||||
|
||||
### Composition patterns
|
||||
|
||||
| Composition type | Prompt anchor phrase |
|
||||
|---|---|
|
||||
| Text-led, dark background | "Bold white sans-serif headline text on deep [colour] background, minimal flat design" |
|
||||
| Text-led, light background | "High-contrast black headline text on clean white background, editorial layout" |
|
||||
| Object/illustration centred | "Centred [object] illustration, [style], [colour] background, title text in upper third" |
|
||||
| Split layout | "Vertical split: left half [colour], right half white. Headline on left side, supporting text on right" |
|
||||
| Photography style | "Photorealistic [scene description], [mood] lighting, [colour] colour grade, text overlay area at [position]" |
|
||||
|
||||
### Style modifiers that work well with Gemini
|
||||
|
||||
- `flat design, no gradients` — clean vector-style outputs
|
||||
- `editorial magazine style` — sophisticated, typographic
|
||||
- `minimal, lots of whitespace` — reduces visual noise
|
||||
- `high contrast, bold typography` — strong thumbnail legibility
|
||||
- `Bauhaus-inspired` — geometric, structured
|
||||
- `dark mode aesthetic` — dark backgrounds with light text
|
||||
- `startup marketing style` — clean, optimistic, sans-serif
|
||||
|
||||
### Negative prompts (always include)
|
||||
|
||||
Append to every prompt:
|
||||
|
||||
```
|
||||
Avoid: stock photography clichés, clipart, excessive gradients, drop shadows,
|
||||
cluttered layout, lens flares, watermarks, low contrast text, AI artefacts.
|
||||
```
|
||||
|
||||
### Text rendering note
|
||||
|
||||
Gemini Imagen sometimes renders short text phrases accurately and longer headlines poorly. If the article headline is longer than 6 words, consider splitting it in the prompt:
|
||||
|
||||
```
|
||||
Primary headline: "[First 4-5 words]"
|
||||
Secondary text: "[Remaining words]"
|
||||
```
|
||||
|
||||
Or instruct the user to add text overlay manually in Canva after generation if legibility is critical.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Cause | Fix |
|
||||
|---|---|---|
|
||||
| `GEMINI_API_KEY not set` | Environment variable missing | Run `export GEMINI_API_KEY="your-key"` and retry |
|
||||
| `ModuleNotFoundError: google.generativeai` | Dependency missing | Run `pip install google-generativeai` |
|
||||
| `No images returned` | Safety filter triggered | Revise prompt to remove any ambiguous language; check that the prompt doesn't describe faces, violence, or brand logos |
|
||||
| Generated image has garbled text | Imagen text rendering limitation | Use shorter headline in prompt, or plan to add text overlay in Canva/Figma post-generation |
|
||||
| Image is the wrong size | Aspect ratio mismatch | Confirm `--width` and `--height` args match one of the supported ratios (16:9, 1:1, 9:16) |
|
||||
| `generate_image.py not found` | Script not created yet | Ask Claude to create it using the template above |
|
||||
| API quota exceeded | Free tier limit | Wait or upgrade to Gemini API paid tier |
|
||||
| Style drift from brand | Prompt not specific enough | Add exact hex codes and specific style descriptors; add stronger negative prompt |
|
||||
|
||||
---
|
||||
|
||||
## Quality Checks
|
||||
|
||||
Before marking the task complete, verify each item:
|
||||
|
||||
- [ ] `GEMINI_API_KEY` environment variable confirmed set before any API calls
|
||||
- [ ] `generate_image.py` script exists in project root — created from template if missing
|
||||
- [ ] All Python dependencies installed and verified (`google-generativeai`, `Pillow`)
|
||||
- [ ] Composition proposals were presented and user confirmed which to generate before any API calls
|
||||
- [ ] Each composition proposal is specific to this article's content — not generic placeholders
|
||||
- [ ] Brand colours (hex codes) are included in the image generation prompts
|
||||
- [ ] Negative prompt appended to every image generation prompt
|
||||
- [ ] Headline text in prompts is 6 words or fewer per text element (longer headlines split or noted as overlay candidates)
|
||||
- [ ] Output folder created at `./thumbnails/[article-slug]/` with correct slug derived from article title
|
||||
- [ ] Files named with candidate number and composition name (`candidate_01_bold_claim.png`)
|
||||
- [ ] Each generated image evaluated via computer vision — not assumed to be correct
|
||||
- [ ] Brand Fit and Text Legibility scores are specific and justified, not round numbers
|
||||
- [ ] Any text rendering issues noted in evaluation with "add text overlay manually" recommendation
|
||||
- [ ] Evaluation report saved as `evaluation_report.md` in the output folder
|
||||
- [ ] At least one recommendation given per use case: web, email/mobile, social
|
||||
- [ ] Full prompts used are included in the evaluation report for user iteration reference
|
||||
- [ ] Iteration offer made after delivering results
|
||||
|
||||
---
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "Create thumbnails for this article"
|
||||
- "Generate cover image candidates for my newsletter"
|
||||
- "Make me 4 thumbnail options for this post"
|
||||
- "Can you generate some thumbnail ideas using Gemini?"
|
||||
- "I need a featured image for this article — use my brand colours"
|
||||
- "Create a thumbnail for this piece using Gemini" [followed by article text or URL]
|
||||
- "Generate article cover images for these brand specs: [colours, style]"
|
||||
- "Make thumbnail candidates and rank them"
|
||||
- "I need newsletter header images — here's the copy"
|
||||
- "Generate and evaluate thumbnail options for this draft"
|
||||
- "Use Gemini to create cover image options"
|
||||
- "Thumbnail this article" [followed by article text]
|
||||
- "Create 3 thumbnail compositions and pick the best one"
|
||||
|
||||
---
|
||||
|
||||
## Cost and Rate Limits
|
||||
|
||||
**Gemini AI Studio free tier (as of early 2026):**
|
||||
- Imagen 3: 10 images per day (free)
|
||||
- Rate limit: varies by region and account tier
|
||||
|
||||
**Paid tier:**
|
||||
- Imagen 3 pricing: approximately $0.03-0.05 per image (check current Google Cloud pricing)
|
||||
- For a typical session generating 4-8 candidates, total cost is under $0.40
|
||||
|
||||
**Recommendation:**
|
||||
- Use the free tier for exploration and iteration
|
||||
- Generate final production candidates on paid tier for higher daily limits
|
||||
- For newsletter teams generating thumbnails weekly, the paid tier is more practical
|
||||
|
||||
---
|
||||
|
||||
*Originally created by Karen Spinner (Wondering About AI) — adapted and extended for this library.*
|
||||
@@ -0,0 +1,531 @@
|
||||
---
|
||||
name: aeo-optimizer
|
||||
description: "Optimize an article for Answer Engine Optimization (AEO) — restructuring content so AI engines like ChatGPT, Perplexity, and Claude can extract, quote, and cite it. Rewrites headings as questions, drops 50-80 word answer capsules, audits paragraph length, and flags trust signals. Use when asked to AEO-optimize, make content AI-readable, improve AI citation chances, or adapt an article for answer engines."
|
||||
---
|
||||
|
||||
# AEO Optimizer Skill
|
||||
|
||||
AEO — Answer Engine Optimization — is the discipline of structuring content so that AI engines (ChatGPT, Perplexity, Claude, Gemini) can extract clean, quotable answers and confidently cite your content as a source.
|
||||
|
||||
Most articles are written for humans who scroll, skim, and click. AI engines don't scroll — they scan for extractable answer units. They look for short, self-contained answer blocks sitting directly beneath a clear question heading. If they can't find those, they either skip the content or paraphrase it poorly. This skill fixes that.
|
||||
|
||||
---
|
||||
|
||||
## The AEO Problem
|
||||
|
||||
Here is what AI engines are scanning for, and what most articles fail to provide:
|
||||
|
||||
| What AI engines want | What most articles deliver |
|
||||
|---|---|
|
||||
| H2 = a direct question ("What is X?") | H2 = a vague topic label ("About X" or "Understanding X") |
|
||||
| 50-80 word answer capsule immediately under the heading | Long intro paragraphs before the actual answer |
|
||||
| No links inside the answer block | Inline links that break extractability |
|
||||
| ≤3 sentences per paragraph | Dense 6-8 sentence paragraphs |
|
||||
| Named frameworks, original data, first-person experience | Generic statements with no attribution or specificity |
|
||||
| Consistent question-answer-expand structure throughout | Inconsistent structure that varies section by section |
|
||||
|
||||
When an AI engine cannot cleanly extract a 50-80 word answer, it either skips the article or provides a vague paraphrase without a citation link. AEO optimization removes those barriers.
|
||||
|
||||
---
|
||||
|
||||
## Required Inputs
|
||||
|
||||
Claude will ask for these if not provided:
|
||||
|
||||
| Input | Required | Notes |
|
||||
|---|---|---|
|
||||
| Article content | Yes | Paste the full draft text, or provide a URL Claude can fetch |
|
||||
| Target audience | No | Helps calibrate question phrasing — e.g. "beginner founders" vs "senior engineers" |
|
||||
| Primary keyword or topic | No | If provided, Claude ensures H2 questions cover it directly |
|
||||
| Existing URL (if published) | No | Used in the audit report to note the live page |
|
||||
| Preserve exact section order | No | Defaults to yes — Claude rewrites in place, doesn't restructure |
|
||||
|
||||
If providing a URL instead of pasted text, Claude will fetch the page content. Note: paywalled or JavaScript-rendered articles may require manual paste.
|
||||
|
||||
---
|
||||
|
||||
## Output Structure
|
||||
|
||||
Claude produces two deliverables in sequence:
|
||||
|
||||
### Deliverable 1 — AEO-Ready Article
|
||||
|
||||
The full rewritten article with:
|
||||
- All H2s rewritten as direct questions
|
||||
- 50-80 word answer capsule inserted directly beneath each H2
|
||||
- Paragraphs trimmed to ≤3 sentences where they exceeded that
|
||||
- Trust signals preserved and lightly emphasized
|
||||
- No links inside any answer capsule
|
||||
- Original voice and structure maintained — this is an optimization, not a rewrite
|
||||
|
||||
**Format:**
|
||||
|
||||
```markdown
|
||||
# [Original H1 title — unchanged unless it needs question format]
|
||||
|
||||
[Introduction — keep as-is or trim to ≤3 sentences. Add a "What this covers:" summary if intro is >150 words.]
|
||||
|
||||
## [H2 rewritten as a direct question?]
|
||||
|
||||
[Answer capsule — 50-80 words, no links, self-contained, answers the question completely on its own.]
|
||||
|
||||
[Rest of the section body — expanded explanation, examples, data, links allowed here]
|
||||
|
||||
## [Next H2 as a direct question?]
|
||||
|
||||
[Answer capsule — 50-80 words, no links]
|
||||
|
||||
[Section body]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Deliverable 2 — AEO Audit Report
|
||||
|
||||
Structured report showing all changes made and signals identified.
|
||||
|
||||
**Format:**
|
||||
|
||||
---
|
||||
|
||||
## AEO Audit Report
|
||||
|
||||
**Article:** [Title]
|
||||
**URL:** [If provided]
|
||||
**Audit date:** [Today's date]
|
||||
**AEO readiness score (before):** [X/10]
|
||||
**AEO readiness score (after):** [X/10]
|
||||
|
||||
---
|
||||
|
||||
### Heading Rewrites
|
||||
|
||||
| Original H2 | Rewritten H2 | Change type |
|
||||
|---|---|---|
|
||||
| Understanding Content Strategy | What is content strategy and why does it matter? | Topic label → direct question |
|
||||
| The Benefits of X | What are the main benefits of X? | Vague noun phrase → question |
|
||||
| How We Do It at [Company] | How does [Company] approach X? | First-person → question format |
|
||||
|
||||
---
|
||||
|
||||
### Answer Capsule Placements
|
||||
|
||||
For each section, confirm capsule word count is within 50-80 words:
|
||||
|
||||
| Section | Capsule word count | Links removed from capsule | Status |
|
||||
|---|---|---|---|
|
||||
| What is content strategy...? | 64 words | 2 links removed | OK |
|
||||
| How do you build a content calendar? | 71 words | 0 links (none were present) | OK |
|
||||
| What tools do content teams use? | 58 words | 1 link removed | OK |
|
||||
|
||||
---
|
||||
|
||||
### Paragraph Length Audit
|
||||
|
||||
| Section | Original max paragraph (sentences) | Action taken |
|
||||
|---|---|---|
|
||||
| Introduction | 6 sentences | Split into 2 paragraphs |
|
||||
| Section 2 body | 4 sentences | Trimmed to 3 |
|
||||
| Section 4 body | 2 sentences | No change needed |
|
||||
|
||||
**Paragraphs flagged as too long (before optimization):** [N]
|
||||
**Paragraphs within ≤3 sentences (after optimization):** [all]
|
||||
|
||||
---
|
||||
|
||||
### Trust Signal Inventory
|
||||
|
||||
Trust signals are the elements AI engines treat as credibility markers — original data, named frameworks, first-person experience, and specific attributions. These make AI engines more likely to cite rather than paraphrase.
|
||||
|
||||
| Signal type | Found in article | Example | AEO value |
|
||||
|---|---|---|---|
|
||||
| Original data / research | Yes | "Our analysis of 400 posts showed..." | High — cite-worthy claim |
|
||||
| Named framework | Yes | "The RICE scoring model" | High — search anchor |
|
||||
| First-person experience | Yes | "After running 3 content audits..." | Medium — authority signal |
|
||||
| Named expert / quote | No | — | Recommend adding |
|
||||
| Specific numbers / stats | Yes | "34% increase in organic traffic" | High — extractable fact |
|
||||
| Date-stamped content | No | — | Recommend adding publication date |
|
||||
| Case study reference | Yes | "At Acme Corp, we ran..." | High — concrete example |
|
||||
|
||||
**Trust signals present:** [N]
|
||||
**Recommended additions:** [list any gaps]
|
||||
|
||||
---
|
||||
|
||||
### AEO Scoring Rubric
|
||||
|
||||
| Criterion | Before | After |
|
||||
|---|---|---|
|
||||
| H2s as direct questions (% of total) | [X%] | [X%] |
|
||||
| Answer capsule present under each H2 | No | Yes |
|
||||
| Capsules within 50-80 words | N/A | [X/N sections] |
|
||||
| No links inside capsules | N/A | Yes |
|
||||
| Paragraphs ≤3 sentences | [X%] | [X%] |
|
||||
| Trust signals present | [N] | [N] |
|
||||
| **Total score** | **[X/10]** | **[X/10]** |
|
||||
|
||||
---
|
||||
|
||||
### Recommended Next Steps
|
||||
|
||||
1. [Any remaining gaps — e.g. "Section 4 capsule is 88 words — trim by 10"]
|
||||
2. [Structural suggestions — e.g. "Add a FAQ section at the end for high-volume PAA questions"]
|
||||
3. [Missing trust signals — e.g. "Add a publication date and last-updated date for freshness signals"]
|
||||
4. [Schema markup suggestion if applicable — FAQ schema, HowTo schema, etc.]
|
||||
|
||||
---
|
||||
|
||||
*End of AEO Audit Report*
|
||||
|
||||
---
|
||||
|
||||
## How Claude Should Execute This Skill
|
||||
|
||||
### Step 1 — Ingest the article
|
||||
|
||||
Accept the content as either:
|
||||
- **Pasted text:** Treat as-is. Do not attempt to fetch a URL if text is pasted.
|
||||
- **URL:** Fetch the page. Extract the main article body — ignore nav, sidebars, footers, and ad blocks. If the page is JavaScript-rendered and fetch returns only a shell, ask the user to paste the text instead.
|
||||
|
||||
Count the headings. Note the number of H2s, H3s, and H1s. This sets expectations for how many capsules will be written.
|
||||
|
||||
### Step 2 — Assess AEO readiness before touching anything
|
||||
|
||||
Before rewriting, score the article on the AEO rubric (see Deliverable 2 scoring table). This gives the user a before/after comparison and helps Claude identify where to focus effort.
|
||||
|
||||
Run through each criterion and note the count:
|
||||
- How many H2s are already in question format? (count ones that end with "?")
|
||||
- Does any section already have a 50-80 word self-contained answer block?
|
||||
- What is the average and maximum paragraph length in sentences?
|
||||
- How many trust signals are present? (scan for numbers, named frameworks, first-person phrases, quotes)
|
||||
|
||||
Record the before scores. Do not round up — be honest.
|
||||
|
||||
### Step 3 — Rewrite H2 headings as questions
|
||||
|
||||
For each H2 in the article, rewrite it as a direct question that a real person would ask an AI engine. Guidelines:
|
||||
|
||||
**The question must:**
|
||||
- Be specific enough that the answer could stand alone as a snippet
|
||||
- Use "What", "How", "Why", "When", "Which", or "Who" — not vague gerunds ("Understanding", "Exploring", "Unpacking")
|
||||
- Match the search intent of the original section, not just rephrase it generically
|
||||
- Be 8 words or fewer when possible (longer questions are harder for AI engines to match)
|
||||
|
||||
**Examples of heading transformations:**
|
||||
|
||||
| Before | After |
|
||||
|---|---|
|
||||
| Introduction to Agile | What is Agile methodology? |
|
||||
| Why We Built This | Why did [Company] build [product]? |
|
||||
| The Case for Async Work | Why do distributed teams choose async work? |
|
||||
| Benefits | What are the main benefits of X? |
|
||||
| Tools and Resources | Which tools do [audience] use for X? |
|
||||
| Getting Started | How do you get started with X? |
|
||||
| Common Mistakes | What mistakes do beginners make with X? |
|
||||
| Our Approach | How does [Company/author] approach X? |
|
||||
|
||||
Do not rewrite H3s unless the user requests it. H3s can stay as labels — AI engines primarily anchor on H2s.
|
||||
|
||||
Do not change the H1. The H1 is the article title and SEO title — it follows different rules.
|
||||
|
||||
### Step 4 — Write answer capsules
|
||||
|
||||
For each H2, write a 50-80 word answer capsule to be inserted immediately after the heading and before any existing body text.
|
||||
|
||||
**Capsule rules:**
|
||||
- Must be self-contained — someone reading only the heading + capsule should have a complete, useful answer
|
||||
- No links of any kind inside the capsule (links break AI extractability)
|
||||
- No hedging phrases ("It depends", "There are many factors") — commit to the answer
|
||||
- Use the same voice and terminology as the article — do not change the author's perspective
|
||||
- If the section has an existing strong first paragraph that is already 50-80 words and self-contained, use it as the capsule with minimal edits rather than writing a new one
|
||||
- Count words precisely — under 50 is too thin, over 80 and AI engines may not extract it cleanly
|
||||
|
||||
**Capsule structure options:**
|
||||
|
||||
Option A — Definition then application:
|
||||
```
|
||||
[Concise definition of the concept in 1-2 sentences.] [How it applies in practice, with one specific example or number.] [Why it matters for the reader's situation.]
|
||||
```
|
||||
|
||||
Option B — Direct answer then context:
|
||||
```
|
||||
[Direct answer to the heading question in 1 sentence.] [2-3 sentences of supporting context, specifics, or mechanism.] [Optional: one concrete example or stat.]
|
||||
```
|
||||
|
||||
Option C — How-to opener:
|
||||
```
|
||||
[State the outcome in 1 sentence.] [Steps 1, 2, 3 in compressed form.] [Note on when this applies or what to watch for.]
|
||||
```
|
||||
|
||||
Mark each capsule clearly with an HTML comment so the author knows it was added:
|
||||
```html
|
||||
<!-- AEO Answer Capsule — 64 words -->
|
||||
[capsule text]
|
||||
<!-- End AEO Capsule -->
|
||||
```
|
||||
|
||||
### Step 5 — Audit and trim paragraph length
|
||||
|
||||
Scan every paragraph in the body sections (not the capsules). If a paragraph exceeds 3 sentences:
|
||||
- Split it into two paragraphs at the most natural break
|
||||
- Do not summarise or remove content — just add a paragraph break
|
||||
- If a paragraph is a list in disguise (long run-on sentence with "and", "then", "also"), convert it to a bullet list instead
|
||||
|
||||
Note every change in the audit report's paragraph length table.
|
||||
|
||||
### Step 6 — Identify and flag trust signals
|
||||
|
||||
Scan the full article for trust signals. Do not add trust signals — only identify what exists and flag gaps. Trust signals are:
|
||||
|
||||
| Signal type | What to look for |
|
||||
|---|---|
|
||||
| Original data | "Our data shows", "We analysed X", "In our survey of N..." |
|
||||
| Named frameworks | Any named methodology, model, or system (RICE, Jobs-to-be-Done, etc.) |
|
||||
| First-person experience | "I found", "We ran", "When I built", "After testing..." |
|
||||
| Specific numbers | Percentages, counts, timeframes, dollar amounts |
|
||||
| Expert quotes | Direct quotes attributed to a named person |
|
||||
| Case studies | Named company or project with specific outcomes |
|
||||
| Publication freshness | A visible publish or update date |
|
||||
|
||||
Flag any category with zero signals as a gap. Include specific recommendations for what could be added (e.g. "Add a statistic to the intro — even a well-known industry stat cited correctly adds credibility").
|
||||
|
||||
### Step 7 — Assemble the output
|
||||
|
||||
Produce the two deliverables in this order:
|
||||
|
||||
1. First: the full AEO-ready article. Use the original markdown structure with the changes applied. Make sure capsules have the HTML comment markers.
|
||||
2. Second: the AEO Audit Report, using the exact table structure from the Output Structure section above.
|
||||
|
||||
Separate the two deliverables with a clear horizontal rule (`---`) and a heading (`## AEO Audit Report`).
|
||||
|
||||
### Step 8 — Optional: FAQ section recommendation
|
||||
|
||||
If the article does not already have a FAQ section, and the topic has obvious high-volume PAA (People Also Ask) questions, recommend adding one. Provide 3-5 suggested FAQ questions in question format with brief capsule answers. Note that FAQ sections with proper schema markup (`FAQPage` JSON-LD) get preferential treatment in both traditional SEO and AI engine extraction.
|
||||
|
||||
---
|
||||
|
||||
## AEO Reference: What Makes a Good Answer Capsule
|
||||
|
||||
This section is reference material — Claude should use it when evaluating capsule quality.
|
||||
|
||||
**Strong capsule (62 words):**
|
||||
> Content strategy is the planning and management of content to achieve specific business goals. It defines what to publish, for whom, through which channels, and how often. A strong content strategy starts with audience research, maps content to stages of the buyer journey, and includes a measurement framework. Without it, content teams produce output without direction — publishing more without knowing whether it drives outcomes.
|
||||
|
||||
Why it works:
|
||||
- Answers the question completely in isolation
|
||||
- No links
|
||||
- Specific enough to be citable (mentions audience research, buyer journey, measurement framework)
|
||||
- Under 80 words
|
||||
|
||||
**Weak capsule (48 words — too short, too vague):**
|
||||
> Content strategy is important for businesses. It helps you plan what content to create. Many companies use content strategy to grow their audience. There are different approaches depending on your goals. It's a broad topic that covers many areas of marketing.
|
||||
|
||||
Why it fails:
|
||||
- Does not complete the answer — "many areas" is not an answer
|
||||
- No specifics, no named concepts
|
||||
- Under 50 words
|
||||
- AI engine would not cite this — it says nothing citable
|
||||
|
||||
---
|
||||
|
||||
## Quality Checks
|
||||
|
||||
Before marking this task complete, verify each item:
|
||||
|
||||
- [ ] Every H2 in the article is now a direct question ending with "?"
|
||||
- [ ] Every question-format H2 has an answer capsule immediately below it (no intervening text)
|
||||
- [ ] Every capsule is between 50 and 80 words — count precisely, not approximately
|
||||
- [ ] No links appear inside any capsule block
|
||||
- [ ] Every capsule has the HTML comment markers noting word count
|
||||
- [ ] Paragraphs throughout the article body are ≤3 sentences (flag any exceptions in the report)
|
||||
- [ ] The H1 title is unchanged
|
||||
- [ ] H3s are unchanged (unless user requested otherwise)
|
||||
- [ ] Original voice, tone, and terminology are preserved — this is optimization, not ghostwriting
|
||||
- [ ] Trust signal inventory table is populated with actual examples from the text, not generic placeholders
|
||||
- [ ] Gaps in trust signals are noted with specific recommendations, not just "add more data"
|
||||
- [ ] Before and after AEO scores are both present in the audit report
|
||||
- [ ] Heading rewrites table is complete — one row per H2
|
||||
- [ ] Paragraph length audit table is complete — covers all sections
|
||||
- [ ] Any FAQ section recommendation is based on real PAA-style questions for the topic, not invented ones
|
||||
- [ ] Both deliverables (article + audit report) are present in the response
|
||||
- [ ] Total word count of the rewritten article is within ±10% of the original (optimization, not expansion)
|
||||
|
||||
---
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "AEO optimize this article"
|
||||
- "Make this content AI-readable"
|
||||
- "Rewrite my headings as questions and add answer capsules"
|
||||
- "Optimize this for ChatGPT and Perplexity to cite"
|
||||
- "Run an AEO audit on this draft"
|
||||
- "Make this article get picked up by AI search"
|
||||
- "I want Perplexity to cite my content — can you fix this article?"
|
||||
- "Turn these headings into questions and add short answer blocks"
|
||||
- "Can you add answer capsules under each section?"
|
||||
- "Audit this for answer engine optimization"
|
||||
- "My content isn't showing up in AI answers — fix the structure"
|
||||
- "AEO this" [followed by article text or URL]
|
||||
- "Optimize for AI citation"
|
||||
- "Make each section self-contained for AI extraction"
|
||||
|
||||
---
|
||||
|
||||
## Appendix: AEO vs SEO — Key Differences
|
||||
|
||||
This is useful context Claude can share with users who are unfamiliar with AEO:
|
||||
|
||||
| Dimension | SEO (Search Engine Optimization) | AEO (Answer Engine Optimization) |
|
||||
|---|---|---|
|
||||
| Target | Google's ranking algorithm | AI engine extraction models |
|
||||
| Primary signal | Backlinks, authority, keyword density | Structured Q&A, answer capsule clarity |
|
||||
| Content format | Long-form, comprehensive coverage | Question-first, capsule-first, then expand |
|
||||
| Heading style | Keyword-rich labels ("Best Project Management Tools") | Direct questions ("What are the best project management tools?") |
|
||||
| Paragraph length | Not a ranking factor | Short (≤3 sentences) is strongly preferred |
|
||||
| Links in body | Important for authority passing | Links inside answer capsules break extractability |
|
||||
| Trust signals | Domain authority, backlink profile | Named data, frameworks, first-person experience |
|
||||
| Measurement | Organic ranking position, CTR | AI citation frequency, answer box appearances |
|
||||
|
||||
AEO does not replace SEO — it complements it. A well-structured article optimized for AEO will also perform better in traditional search because its structure is clearer and its headings are more specific to user intent.
|
||||
|
||||
---
|
||||
|
||||
## Appendix: Answer Capsule Templates by Content Type
|
||||
|
||||
Not all articles have the same kind of content. Use these capsule templates as starting points based on the section type.
|
||||
|
||||
### "What is X?" sections (definition)
|
||||
|
||||
```
|
||||
[X] is [concise category or type]. It [what it does or how it works] by [mechanism or method].
|
||||
[Why it exists or what problem it solves — 1 sentence.] [One concrete example or real-world application.]
|
||||
```
|
||||
|
||||
Target: 55-70 words. Avoid starting with "X is a type of X" — give immediate signal.
|
||||
|
||||
### "How do you do X?" sections (how-to)
|
||||
|
||||
```
|
||||
To [achieve outcome], [do step A], then [do step B], then [do step C].
|
||||
[The most common mistake or prerequisite — 1 sentence.] [The expected result or timeframe.]
|
||||
```
|
||||
|
||||
Target: 50-65 words. Use active verbs throughout. No links.
|
||||
|
||||
### "Why does X matter?" sections (rationale)
|
||||
|
||||
```
|
||||
[X] matters because [specific reason 1] and [specific reason 2].
|
||||
Without [X], [consequence — ideally quantified or concrete].
|
||||
[Who this is most important for, and under what conditions.]
|
||||
```
|
||||
|
||||
Target: 55-75 words. Specifics outperform generalities here — name numbers when they exist.
|
||||
|
||||
### "What are the benefits of X?" sections (list rationale)
|
||||
|
||||
```
|
||||
The main benefits of [X] are [benefit 1], [benefit 2], and [benefit 3].
|
||||
[Benefit 1] means [specific outcome]. [Benefit 2] enables [specific use case].
|
||||
Together these make [X] valuable for [audience] who need [outcome].
|
||||
```
|
||||
|
||||
Target: 60-80 words. Compress the list into prose — bullet lists inside capsules are less extractable.
|
||||
|
||||
### "Which X should I choose?" sections (comparison/decision)
|
||||
|
||||
```
|
||||
Choose [Option A] when [condition A]. Choose [Option B] when [condition B].
|
||||
The deciding factor is [key variable]. [One sentence on the most common mistake —
|
||||
picking based on the wrong criterion.]
|
||||
```
|
||||
|
||||
Target: 50-70 words. Decision capsules are among the highest-cited by AI engines — they answer the user's actual next question.
|
||||
|
||||
### "When should I X?" sections (timing/trigger)
|
||||
|
||||
```
|
||||
[X] when [specific trigger condition], typically [timeframe or frequency].
|
||||
Early signs that it's time include [signal 1] and [signal 2].
|
||||
Waiting too long often results in [consequence].
|
||||
```
|
||||
|
||||
Target: 45-65 words. Concise is especially important for timing capsules.
|
||||
|
||||
---
|
||||
|
||||
## Appendix: AEO Scoring Rubric — Detailed Criteria
|
||||
|
||||
Use this when producing the before/after score. Each criterion has a maximum contribution to the /10 score.
|
||||
|
||||
| Criterion | Max score | How to assess |
|
||||
|---|---|---|
|
||||
| H2s as direct questions | 2 pts | 2 = all H2s are questions; 1 = majority; 0 = few or none |
|
||||
| Answer capsules present | 2 pts | 2 = every H2 section has a capsule; 1 = some sections; 0 = none |
|
||||
| Capsules within 50-80 words | 1 pt | 1 = all capsules in range; 0 = any over 80 or under 50 |
|
||||
| No links inside capsules | 1 pt | 1 = zero links in any capsule; 0 = any links present |
|
||||
| Paragraphs ≤3 sentences | 2 pts | 2 = all paragraphs compliant; 1 = majority; 0 = widespread violations |
|
||||
| Trust signals present | 2 pts | 2 = 3+ trust signal types; 1 = 1-2 types; 0 = none |
|
||||
|
||||
**Score interpretation:**
|
||||
- 8-10: Strong AEO readiness — well-positioned for AI citation
|
||||
- 5-7: Partial — likely extracted occasionally but inconsistently
|
||||
- 0-4: Low readiness — AI engines will paraphrase at best, skip at worst
|
||||
|
||||
A typical unoptimized article scores 2-4. A well-structured but unoptimized thought leadership piece might score 4-6. After this skill runs, target 8+.
|
||||
|
||||
---
|
||||
|
||||
## Appendix: How Different AI Engines Extract Content
|
||||
|
||||
Understanding how each engine works helps explain the rules behind the skill.
|
||||
|
||||
### ChatGPT (GPT-4 and later) / Bing
|
||||
|
||||
Retrieval-augmented generation with Bing Search integration. When a user asks a question, Bing retrieves pages, then GPT extracts passages. It tends to extract the first plausible answer-shaped block it finds in the page — meaning the capsule directly under the H2 is almost always what gets quoted. It prefers prose over lists for citations (though it reads lists fine).
|
||||
|
||||
**Implication:** Get the capsule under the question-format H2 right. The rest of the section body is bonus context.
|
||||
|
||||
### Perplexity
|
||||
|
||||
Explicitly designed for sourced Q&A. It retrieves 5-10 pages per query and extracts from all of them simultaneously. It shows citations with numbered footnotes. It strongly prefers content that is:
|
||||
- Clearly attributed (author name or publication byline visible)
|
||||
- Recently published or updated (freshness signal)
|
||||
- Structured around the question being asked (heading match)
|
||||
|
||||
**Implication:** Trust signals (author, date) and heading-to-question matching are especially important for Perplexity. Capsules that include specific numbers or named frameworks are more likely to be footnoted.
|
||||
|
||||
### Claude (Anthropic)
|
||||
|
||||
Claude with web search capability (Claude.ai or API with tools) retrieves pages and synthesises across them. Claude prioritises self-contained, complete answers and tends to directly quote capsules that are within the 50-80 word range. Claude is less likely to quote incomplete paragraphs that trail off or rely on surrounding context.
|
||||
|
||||
**Implication:** The self-contained requirement is especially important for Claude citation. If the capsule requires reading the surrounding sentences to make sense, Claude will paraphrase instead of quote.
|
||||
|
||||
### Google Gemini (AI Overviews)
|
||||
|
||||
Integrated into Google Search. Generates AI Overviews for informational queries. Extracts from indexed pages, with preference for pages that already rank well (so SEO and AEO reinforce each other here). Tends to extract bulleted lists and numbered steps for how-to content; extracts definition capsules for "what is" queries.
|
||||
|
||||
**Implication:** For Gemini AI Overviews, structured how-to content with numbered steps in the capsule performs well. Definition capsules should include the category/type as the first word.
|
||||
|
||||
---
|
||||
|
||||
## Appendix: Content Types That Benefit Most from AEO
|
||||
|
||||
Not all content benefits equally. Use this to set expectations with the user about where AEO investment pays off most.
|
||||
|
||||
| Content type | AEO benefit | Reason |
|
||||
|---|---|---|
|
||||
| Glossary or definition articles | Very high | AI engines are constantly answering "what is X?" queries |
|
||||
| How-to guides and tutorials | Very high | Step-by-step content is a primary retrieval target |
|
||||
| Comparison articles ("X vs Y") | High | Decision queries are common AI engine inputs |
|
||||
| FAQ pages | High | Already in question format — just needs capsule discipline |
|
||||
| Research roundups with original data | High | Named statistics are citation anchors |
|
||||
| Thought leadership / opinion pieces | Medium | Opinion is less extractable; add definition and how-to sections |
|
||||
| News and timely content | Medium | AI engines prefer evergreen; but breaking news gets citation bursts |
|
||||
| Case studies | Medium | Specific outcomes are extractable; company-specific context less so |
|
||||
| Creative writing / narrative | Low | Not structured for extraction; AEO rules don't apply |
|
||||
| Product pages / landing pages | Low | Conversion-focused pages are rarely cited by AI engines |
|
||||
|
||||
---
|
||||
|
||||
*Originally created by Gencay (LearnAIwithMe) — adapted and extended for this library.*
|
||||
@@ -0,0 +1,282 @@
|
||||
---
|
||||
name: claude-superpowers
|
||||
description: "Force Claude Code to work like a senior developer: plan before coding, work in isolation, write tests first, and review its own output twice before presenting it. Use when asked to enable superpowers mode, activate the superpowers framework, or turn on superpowers for this session. Installs a 4-stage framework — Plan, Isolate, Test First, Double Review — that prevents Claude from sprinting into broken code."
|
||||
---
|
||||
|
||||
# Claude Superpowers Skill
|
||||
|
||||
Stop Claude from shipping the first thing it writes. Superpowers mode locks Claude into four stages — Plan, Isolate, Test First, Double Review — so that what it presents at the end is actually right.
|
||||
|
||||
The default problem: Claude sprints out of the gate, writes the whole thing in one shot, and it looks great — until someone runs it. It doesn't plan. It doesn't test. It doesn't verify. The result: code that breaks on edge cases, debugging rounds that burn tokens, and rework that costs more than doing it right the first time.
|
||||
|
||||
> **Credit:** Inspired by a skill from Nate Herk's YouTube channel — adapted and extended for this library.
|
||||
|
||||
---
|
||||
|
||||
## Required Inputs
|
||||
|
||||
No inputs required. Superpowers activates on command, then applies to whatever coding task follows.
|
||||
|
||||
---
|
||||
|
||||
## The Four Stages
|
||||
|
||||
### Stage 1 — Plan
|
||||
|
||||
Before writing a single line of code, Claude must produce a written plan and wait for user confirmation.
|
||||
|
||||
**Plan format:**
|
||||
|
||||
```
|
||||
PLAN
|
||||
════
|
||||
|
||||
TASK
|
||||
[One-sentence restatement of what was asked. If anything is ambiguous, flag it here before proceeding.]
|
||||
|
||||
APPROACH
|
||||
[2–4 sentences describing the implementation approach and key decisions. If there are multiple valid approaches, briefly explain why this one was chosen.]
|
||||
|
||||
FILES TO CREATE OR MODIFY
|
||||
- [path/to/file.ts] — [what changes: create / modify / delete — one line reason]
|
||||
- [path/to/file.ts] — [what changes]
|
||||
|
||||
EDGE CASES I WILL HANDLE
|
||||
- [Edge case 1]
|
||||
- [Edge case 2]
|
||||
- [Edge case 3]
|
||||
|
||||
EDGE CASES I AM NOT HANDLING (out of scope)
|
||||
- [Out of scope case — reason]
|
||||
|
||||
ASSUMPTIONS
|
||||
- [Any assumption made where the requirements were unclear]
|
||||
|
||||
Confirm this plan before I start coding.
|
||||
```
|
||||
|
||||
Claude must not proceed until the user says yes (or provides corrections). If the user corrects the plan, revise and re-confirm before starting.
|
||||
|
||||
---
|
||||
|
||||
### Stage 2 — Isolate
|
||||
|
||||
Claude works in isolation until the output is complete and reviewed. Nothing touches the main project until explicitly approved.
|
||||
|
||||
**Isolation rules:**
|
||||
- If git is available: create a feature branch before making any changes. Branch name format: `superpowers/[task-slug]`
|
||||
- If no git: note that changes are being made to a working copy and flag all modified files at the end for user review before they're considered "shipped"
|
||||
- Do not modify files outside the scope defined in the plan unless the user explicitly expands scope during the session
|
||||
- If new scope is discovered mid-task (e.g. a dependency needs to change), surface it: "This requires also modifying [X] — should I include that in scope?"
|
||||
|
||||
**On starting Stage 2, announce:**
|
||||
```
|
||||
ISOLATE
|
||||
Working in isolation on branch: superpowers/[task-slug]
|
||||
No changes will be considered final until Stage 4 review is complete.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Stage 3 — Test First
|
||||
|
||||
Before writing the implementation, write the tests (or at minimum, define the expected behaviour as executable assertions).
|
||||
|
||||
**Test-first approach:**
|
||||
1. Write tests that define the expected behaviour for the task
|
||||
2. Write tests that cover each edge case identified in the plan
|
||||
3. Run the tests — they should fail (implementation doesn't exist yet)
|
||||
4. Confirm the tests are failing for the right reason before writing implementation
|
||||
5. Write the implementation
|
||||
6. Run the tests — they should now pass
|
||||
7. If tests fail: fix the implementation, not the tests
|
||||
|
||||
**If the project has no test setup:** flag it and offer two options:
|
||||
- Option A: Set up a minimal test harness before proceeding (recommended)
|
||||
- Option B: Define the expected behaviour as a checklist of manual verification steps (faster but weaker)
|
||||
|
||||
**Test summary to show before writing implementation:**
|
||||
|
||||
```
|
||||
TESTS WRITTEN
|
||||
─────────────
|
||||
File: [test file path]
|
||||
Tests:
|
||||
✗ [test description — covers: happy path]
|
||||
✗ [test description — covers: edge case 1]
|
||||
✗ [test description — covers: edge case 2]
|
||||
✗ [test description — covers: error state]
|
||||
|
||||
All tests failing as expected. Starting implementation.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Stage 4 — Double Review
|
||||
|
||||
After completing the code and running tests, Claude reviews its own work twice before presenting it. Neither review is a formality.
|
||||
|
||||
**Review 1 — "Does this match what was asked for?"**
|
||||
|
||||
Check the completed code against the original request and confirmed plan:
|
||||
- Does it do everything that was asked?
|
||||
- Does it handle all edge cases from the plan?
|
||||
- Are there any mismatches between what was planned and what was built?
|
||||
- Are there any assumptions baked in that weren't confirmed?
|
||||
|
||||
**Review 2 — "Is this good code?"**
|
||||
|
||||
Check for technical quality independent of the requirements:
|
||||
- Obvious bugs or logic errors
|
||||
- Missing error handling (especially at boundaries: API calls, file I/O, user input)
|
||||
- Security issues (injection vulnerabilities, exposed secrets, missing auth checks)
|
||||
- Readability: would another developer understand this in 6 months?
|
||||
- Performance: any obvious inefficiencies on the critical path?
|
||||
- Dead code or unused imports introduced
|
||||
|
||||
**Double Review output format:**
|
||||
|
||||
```
|
||||
REVIEW 1 — CORRECTNESS
|
||||
───────────────────────
|
||||
✅ Handles [requirement 1]
|
||||
✅ Handles [requirement 2]
|
||||
✅ Edge case [X] covered
|
||||
⚠️ [Issue found — what it is and what was changed to fix it]
|
||||
|
||||
REVIEW 2 — CODE QUALITY
|
||||
────────────────────────
|
||||
✅ Error handling present at all API boundaries
|
||||
✅ No obvious security issues
|
||||
⚠️ [Issue found — what it was and how it was fixed]
|
||||
✅ Readable — no unexplained complexity
|
||||
|
||||
VERDICT: [Ready to present / Fixed N issues before presenting]
|
||||
```
|
||||
|
||||
If issues are found in either review, fix them and note what was fixed. Present the corrected version, not the original draft.
|
||||
|
||||
---
|
||||
|
||||
## Activation Response
|
||||
|
||||
When the user triggers Superpowers mode, respond with:
|
||||
|
||||
```
|
||||
Superpowers mode active.
|
||||
|
||||
I'll work in 4 stages for every coding task this session:
|
||||
1. PLAN — Write a plan and wait for your confirmation before coding
|
||||
2. ISOLATE — Work on a branch; nothing ships until you approve
|
||||
3. TEST — Write tests before the implementation
|
||||
4. REVIEW — Review my own work twice before presenting it
|
||||
|
||||
What are we building?
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Output Structure
|
||||
|
||||
### Full task flow (all four stages)
|
||||
|
||||
```
|
||||
PLAN
|
||||
════
|
||||
[Plan format as above]
|
||||
Confirm this plan before I start coding.
|
||||
|
||||
---
|
||||
[User confirms]
|
||||
---
|
||||
|
||||
ISOLATE
|
||||
Working in isolation on branch: superpowers/[task-slug]
|
||||
|
||||
TESTS WRITTEN
|
||||
─────────────
|
||||
[Test summary — all failing]
|
||||
Starting implementation.
|
||||
|
||||
---
|
||||
[Implementation runs]
|
||||
---
|
||||
|
||||
REVIEW 1 — CORRECTNESS
|
||||
───────────────────────
|
||||
[Checklist]
|
||||
|
||||
REVIEW 2 — CODE QUALITY
|
||||
────────────────────────
|
||||
[Checklist]
|
||||
|
||||
VERDICT: Ready to present.
|
||||
|
||||
---
|
||||
|
||||
COMPLETE
|
||||
════════
|
||||
[Summary of what was built, files created/modified, how to run/test it]
|
||||
Branch: superpowers/[task-slug] — merge when ready.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CLAUDE.md Installation Text
|
||||
|
||||
After activating Superpowers for the session, provide the user with the exact text to add to their `CLAUDE.md` to make it permanent:
|
||||
|
||||
````
|
||||
```
|
||||
## Superpowers Framework
|
||||
|
||||
This framework is always active for coding tasks in this project.
|
||||
|
||||
### Stage 1 — Plan
|
||||
Before writing any code: produce a written plan including task restatement, approach, files to create/modify, edge cases to handle, and assumptions. Wait for explicit user confirmation before proceeding.
|
||||
|
||||
### Stage 2 — Isolate
|
||||
Work on a feature branch (superpowers/[task-slug]) or clearly flagged working copy. Nothing is considered shipped until the user approves after Stage 4.
|
||||
|
||||
### Stage 3 — Test First
|
||||
Write tests before writing the implementation. Tests should fail before implementation, pass after. If no test setup exists, offer to create one or produce a manual verification checklist.
|
||||
|
||||
### Stage 4 — Double Review
|
||||
After completing code, run two reviews before presenting:
|
||||
- Review 1: Does this match what was asked for? Check against original request and plan.
|
||||
- Review 2: Is this good code? Check for bugs, missing error handling, security issues, readability.
|
||||
Fix any issues found. Present the corrected version. Show the review checklist.
|
||||
```
|
||||
````
|
||||
|
||||
Tell the user: "Add this to your CLAUDE.md and Superpowers will be active permanently for this project."
|
||||
|
||||
---
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] Stage 1 plan was shown and user explicitly confirmed before any code was written
|
||||
- [ ] Plan includes: task restatement, approach, files to modify, edge cases in scope, edge cases out of scope, assumptions
|
||||
- [ ] Ambiguities in the original request were flagged in the plan (not silently assumed)
|
||||
- [ ] Stage 2 isolation: a feature branch was created (or flagged as working copy if no git)
|
||||
- [ ] Stage 3 tests were written before implementation — not after
|
||||
- [ ] Tests were run and confirmed to be failing before implementation started
|
||||
- [ ] Stage 4 Review 1 checked against the original request — not just against the plan
|
||||
- [ ] Stage 4 Review 2 checked for bugs, error handling, security, readability — all four
|
||||
- [ ] Issues found in either review were fixed before presenting — not flagged as "things to fix later"
|
||||
- [ ] Final output shows what was built, which files were changed, and how to run/test it
|
||||
- [ ] CLAUDE.md installation text was offered after activation
|
||||
|
||||
---
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "Enable superpowers mode"
|
||||
- "Activate superpowers"
|
||||
- "Turn on superpowers for this session"
|
||||
- "Use the superpowers framework"
|
||||
- "Make sure you plan before coding"
|
||||
- "I want you to review your work before showing me"
|
||||
- "Write tests first this time"
|
||||
- "Slow down and plan it out before you start building"
|
||||
- "Work on a branch and show me a plan before touching anything"
|
||||
@@ -0,0 +1,248 @@
|
||||
---
|
||||
name: context-mode
|
||||
description: "Activate output filtering, session logging, and auto-resume to keep Claude Code sessions running for hours without context bloat or memory loss. Use when asked to enable context mode, turn on long session mode, or activate session persistence. Installs a session log at project root, filters verbose command output before it enters context, and auto-resumes after Claude resets."
|
||||
---
|
||||
|
||||
# Context Mode Skill
|
||||
|
||||
Fix the two session killers that end most Claude Code sessions in under 30 minutes: context bloat from raw command output, and memory loss after a reset.
|
||||
|
||||
Context Mode runs three systems simultaneously to keep sessions alive:
|
||||
|
||||
- **Output Filtering** — strips verbose command output before it enters context
|
||||
- **Session Log** — writes a running log of everything that happened
|
||||
- **Auto-Resume** — reads the log on reset and picks up exactly where you left off
|
||||
|
||||
> **Credit:** Inspired by a skill from Nate Herk's YouTube channel — adapted and extended for this library.
|
||||
|
||||
---
|
||||
|
||||
## Required Inputs
|
||||
|
||||
No inputs required. Context Mode activates on command.
|
||||
|
||||
Optional: user can specify a custom log file path if they don't want `session.log` in the project root.
|
||||
|
||||
---
|
||||
|
||||
## How Context Mode Works
|
||||
|
||||
### Part 1 — Output Filtering
|
||||
|
||||
The problem: every time Claude Code runs a command, the full raw output enters the context window. A single `npm install` can dump hundreds of lines. A test suite run? Thousands. Within 30 minutes, the context is full of noise and Claude resets.
|
||||
|
||||
The fix: before any command output enters context, filter it to the useful summary only.
|
||||
|
||||
**What gets kept:**
|
||||
- Last 10 lines of stdout
|
||||
- Every line containing `error`, `warn`, `fail`, `exception`, `traceback`, or `fatal` (case-insensitive)
|
||||
- The exit code
|
||||
- A one-line summary of what the command did and whether it succeeded
|
||||
|
||||
**What gets discarded:**
|
||||
- Middle section of long stdout (replaced with `[... N lines of output truncated ...]`)
|
||||
- Progress bars, download indicators, verbose install logs
|
||||
- Repeated identical lines (deduplicated)
|
||||
|
||||
**Filtering summary format:**
|
||||
|
||||
```
|
||||
COMMAND: [command run]
|
||||
STATUS: [exit code — success / failed]
|
||||
SUMMARY: [one sentence: what happened]
|
||||
ERRORS: [any error/warn lines — or "none"]
|
||||
TAIL: [last 10 lines of stdout]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Part 2 — Session Log
|
||||
|
||||
Claude maintains a running log file at `[project root]/session.log`. This file is written after every significant action and is the source of truth for resuming after a reset.
|
||||
|
||||
**Session log format:**
|
||||
|
||||
```
|
||||
SESSION LOG
|
||||
===========
|
||||
Started: [timestamp]
|
||||
Branch: [current git branch]
|
||||
Directory: [working directory]
|
||||
|
||||
FILES EDITED
|
||||
────────────
|
||||
[timestamp] [file path] — [one-line description of what changed]
|
||||
|
||||
COMMANDS RUN
|
||||
────────────
|
||||
[timestamp] [command] — [outcome: success / failed — brief reason]
|
||||
|
||||
TASKS IN PROGRESS
|
||||
─────────────────
|
||||
[ ] [Task description — what's been done so far and what's left]
|
||||
[x] [Completed task]
|
||||
|
||||
LAST USER PROMPT
|
||||
────────────────
|
||||
[The most recent instruction from the user, verbatim]
|
||||
|
||||
LAST ACTION TAKEN
|
||||
─────────────────
|
||||
[What Claude did last, in one sentence]
|
||||
```
|
||||
|
||||
**Log update rules:**
|
||||
- Write to `session.log` after every file edit
|
||||
- Write to `session.log` after every command run
|
||||
- Update "Tasks in Progress" when a task is started, progressed, or completed
|
||||
- Always overwrite "Last User Prompt" and "Last Action Taken" with the current values — don't append, replace
|
||||
|
||||
---
|
||||
|
||||
### Part 3 — Resume on Reset
|
||||
|
||||
When a new Claude session starts, the first action is:
|
||||
|
||||
1. Check for `session.log` in the project root
|
||||
2. If found, read it and announce the resume:
|
||||
|
||||
```
|
||||
Resuming session.
|
||||
|
||||
Branch: [branch]
|
||||
Last working on: [last task in progress]
|
||||
Files edited: [list from session log]
|
||||
Tasks pending: [incomplete tasks]
|
||||
Last prompt: "[last user prompt]"
|
||||
|
||||
Continuing from where we left off.
|
||||
```
|
||||
|
||||
3. Continue with the next logical step — don't ask "what should I do?" — check the task list and carry on
|
||||
|
||||
If no `session.log` exists, start fresh and initialise the log.
|
||||
|
||||
---
|
||||
|
||||
## Activation Response
|
||||
|
||||
When the user triggers Context Mode, respond with:
|
||||
|
||||
```
|
||||
Context Mode active.
|
||||
|
||||
Session log initialised at: [absolute path to session.log]
|
||||
Output filtering: enabled
|
||||
Auto-resume: enabled
|
||||
|
||||
I'll maintain your session state across resets. Long sessions won't lose context.
|
||||
```
|
||||
|
||||
Then immediately initialise `session.log` with the current timestamp, branch, and directory.
|
||||
|
||||
---
|
||||
|
||||
## Output Structure
|
||||
|
||||
### On activation
|
||||
|
||||
```
|
||||
Context Mode active.
|
||||
Session log initialised at: [path]
|
||||
Output filtering: enabled
|
||||
Auto-resume: enabled
|
||||
I'll maintain your session state across resets. Long sessions won't lose context.
|
||||
```
|
||||
|
||||
### On command execution (filtered output format)
|
||||
|
||||
```
|
||||
COMMAND: npm test
|
||||
STATUS: exit 1 — failed
|
||||
SUMMARY: 47 tests passed, 3 failed in auth.test.ts
|
||||
ERRORS: Error: Expected 200, received 401 (line 84)
|
||||
Error: Token not found in response (line 112)
|
||||
TAIL:
|
||||
✓ login with valid credentials (23ms)
|
||||
✓ logout clears session (11ms)
|
||||
✗ refresh token after expiry
|
||||
...
|
||||
```
|
||||
|
||||
### On reset / new session (resume announcement)
|
||||
|
||||
```
|
||||
Resuming session.
|
||||
|
||||
Branch: feature/auth-refresh
|
||||
Last working on: Fixing token refresh logic in auth.service.ts
|
||||
Files edited: src/auth/auth.service.ts, src/auth/auth.test.ts
|
||||
Tasks pending: [ ] Fix failing test on line 112
|
||||
[ ] Run full test suite once fix is applied
|
||||
Last prompt: "The refresh token test is still failing — look at the 401 handling"
|
||||
|
||||
Continuing from where we left off.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CLAUDE.md Installation Text
|
||||
|
||||
After activating Context Mode for the session, provide the user with the exact text to add to their `CLAUDE.md` to make it permanent across all sessions:
|
||||
|
||||
````
|
||||
```
|
||||
## Context Mode
|
||||
|
||||
Context Mode is always active in this project.
|
||||
|
||||
### Output Filtering
|
||||
Before any command output enters context, filter it to:
|
||||
- Last 10 lines of stdout
|
||||
- Any lines containing: error, warn, fail, exception, traceback, fatal (case-insensitive)
|
||||
- Exit code
|
||||
- One-line summary of what the command did
|
||||
|
||||
Use this format for filtered output:
|
||||
COMMAND: [command]
|
||||
STATUS: [exit code — success/failed]
|
||||
SUMMARY: [one sentence]
|
||||
ERRORS: [error lines or "none"]
|
||||
TAIL: [last 10 lines]
|
||||
|
||||
### Session Log
|
||||
Maintain a running session log at ./session.log. Write to it after every file edit and every command run. Track: files edited, commands run, tasks in progress, last user prompt, last action taken. Format defined in Context Mode skill.
|
||||
|
||||
### Auto-Resume
|
||||
At the start of every new session, check for ./session.log. If it exists, read it and announce the resume state. Continue from the last task in progress without asking for instructions.
|
||||
```
|
||||
````
|
||||
|
||||
Tell the user: "Add this to your CLAUDE.md and Context Mode will be active permanently for this project — even after you close and reopen the session."
|
||||
|
||||
---
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] `session.log` was initialised immediately on activation (not deferred)
|
||||
- [ ] Log path shown to user is the absolute path, not relative
|
||||
- [ ] Output filtering is applied on the very next command run — not just announced
|
||||
- [ ] Filtered output format includes: command, status, summary, errors, and tail — all five fields
|
||||
- [ ] Session log tracks all four categories: files edited, commands run, tasks in progress, last prompt
|
||||
- [ ] Resume announcement reads the actual log contents — not a generic template
|
||||
- [ ] On resume, Claude continues the work without prompting the user for instructions
|
||||
- [ ] CLAUDE.md installation text was offered after activation
|
||||
- [ ] Log update rule is clear: "Last User Prompt" and "Last Action Taken" replace previous values, not append
|
||||
|
||||
---
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "Enable context mode"
|
||||
- "Turn on context mode for this session"
|
||||
- "Activate long session mode"
|
||||
- "I keep losing context — fix it"
|
||||
- "Set up session logging"
|
||||
- "Keep track of what you've done so you can resume after a reset"
|
||||
- "Enable output filtering to save context"
|
||||
- "Set up auto-resume so we don't lose our place"
|
||||
@@ -0,0 +1,186 @@
|
||||
---
|
||||
name: email-triage
|
||||
description: Reads your Gmail inbox for a configurable window (default: last 8 hours) and surfaces only what needs action — replies, decisions, or follow-up. Filters out receipts, notifications, newsletters, and anything that doesn't need you.
|
||||
---
|
||||
|
||||
# Email Triage
|
||||
|
||||
## The Problem
|
||||
|
||||
Most of us spend real time triaging email that could be sorted automatically. Scrolling through a mixed inbox of newsletters, order confirmations, Jira notifications, and actual human asks is a tax on focus. The 40 emails since lunch contain maybe 4 that actually need you — this skill finds those 4.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
| Requirement | Details |
|
||||
|-------------|---------|
|
||||
| Gmail connector | Must be active in Claude settings (Settings → Connectors → Gmail) |
|
||||
| Gmail account | The account you want triaged |
|
||||
|
||||
If the Gmail connector is not connected, Claude will prompt you to connect it before proceeding.
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Required | Default | Notes |
|
||||
|-------|----------|---------|-------|
|
||||
| Time window | No | Last 8 hours | Accepts: "last 8 hours", "last 24h", "today", "since Monday", "last 3 days" |
|
||||
| Always-include senders | No | None | Specific names or email addresses that always surface, regardless of content |
|
||||
| Always-ignore senders | No | None | Domains or addresses to always suppress (e.g. noreply@*, jira@company.com) |
|
||||
| Focus area | No | None | Optional context: "focus on anything from clients" or "flag anything about the launch" |
|
||||
|
||||
## What Gets Filtered Out
|
||||
|
||||
Claude suppresses the following categories. They are counted in the summary but not shown:
|
||||
|
||||
- Order confirmations and shipping notifications
|
||||
- Marketing and promotional emails (including "one-time" offer emails)
|
||||
- Newsletter subscriptions and digest emails
|
||||
- Automated system notifications (monitoring alerts, CI/CD, build reports)
|
||||
- Calendar invites that have already been accepted or declined
|
||||
- Read receipts and delivery confirmations
|
||||
- Social media notifications (LinkedIn, Twitter/X, etc.)
|
||||
- Internal ticket updates unless the ticket is assigned to you and requires action
|
||||
- Bank and financial statements (surfaced count only, not content)
|
||||
|
||||
## What Gets Surfaced
|
||||
|
||||
Claude surfaces only emails that meet one or more of these criteria:
|
||||
|
||||
- A human is waiting for a reply
|
||||
- A decision is being requested
|
||||
- There is a deadline or time-sensitive ask, explicit or implied
|
||||
- The sender is someone who does not usually email you (potential priority signal)
|
||||
- The email is from a sender in your always-include list
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
## Inbox Triage — [Time window] | [Date], [Time]
|
||||
**Total emails scanned:** X | **Actionable:** Y | **Filtered out:** Z
|
||||
|
||||
---
|
||||
|
||||
### 🔴 High Priority — Needs reply or decision today
|
||||
|
||||
**From:** [Name] <email@domain.com>
|
||||
**Subject:** [Subject line]
|
||||
**Received:** [Time, e.g. 2:14 PM]
|
||||
**What they need:** [One sentence — the actual ask, not a summary of the email]
|
||||
**Reply starter:** "[A draft opener they can continue — 1 sentence max]"
|
||||
|
||||
---
|
||||
|
||||
**From:** [Name] <email@domain.com>
|
||||
**Subject:** [Subject line]
|
||||
**Received:** [Time]
|
||||
**What they need:** [One sentence]
|
||||
**Reply starter:** "[Draft opener]"
|
||||
|
||||
---
|
||||
|
||||
### 🟡 Medium Priority — Reply within 24–48h
|
||||
|
||||
**From:** [Name] <email@domain.com>
|
||||
**Subject:** [Subject line]
|
||||
**Received:** [Time]
|
||||
**What they need:** [One sentence]
|
||||
**Reply starter:** "[Draft opener]" *(or "No reply needed — action only: [what to do]")*
|
||||
|
||||
---
|
||||
|
||||
### 🟢 FYI — Worth knowing, no action required
|
||||
|
||||
- **[Name]** re: [Subject] — [One-line summary of why it might be relevant]
|
||||
- **[Name]** re: [Subject] — [One-line summary]
|
||||
|
||||
---
|
||||
|
||||
### ⚪ Filtered Out — [Z emails]
|
||||
Receipts: X | Newsletters: X | Notifications: X | Other automated: X
|
||||
*(No action needed — not shown in detail)*
|
||||
```
|
||||
|
||||
## Instructions for Claude
|
||||
|
||||
### Step 1 — Connect and confirm the time window
|
||||
|
||||
Confirm the Gmail connector is active. Parse the requested time window and translate it to an exact datetime range (e.g. "last 8 hours" = [current time minus 8 hours] to now). State the window at the top of the output.
|
||||
|
||||
### Step 2 — Read the inbox
|
||||
|
||||
Fetch emails from the inbox for the specified time window. Include: sender name, sender email, subject, received time, and email body (or first 500 words if long). Do not fetch emails older than the window.
|
||||
|
||||
### Step 3 — Apply ignore rules
|
||||
|
||||
If the user specified always-ignore senders or domains, suppress those immediately. If no ignore list was given, apply standard suppression (see What Gets Filtered Out). Track counts for the filtered summary.
|
||||
|
||||
### Step 4 — Classify each remaining email
|
||||
|
||||
For each non-suppressed email, classify into one of four categories:
|
||||
|
||||
- **High Priority**: A human is waiting on a reply today, or there is an explicit deadline within 24 hours
|
||||
- **Medium Priority**: A reply is needed but not urgently, or there is an implicit ask without a hard deadline
|
||||
- **FYI**: No action needed, but the user would likely want to know about it
|
||||
- **Filtered Out**: Falls into a suppressed category — add to count, do not show
|
||||
|
||||
Apply the always-include list after classification: any email from a flagged sender surfaces regardless of category, with its actual classification.
|
||||
|
||||
### Step 5 — Write the "What they need" line
|
||||
|
||||
This is the highest-value part of the output. Write exactly one sentence that captures the actual ask — not a summary of the email, the ask.
|
||||
|
||||
Bad: "Sarah sent an email about the Q3 report."
|
||||
Good: "Sarah needs your sign-off on the Q3 report before she sends it to the board at 5 PM."
|
||||
|
||||
If there is no clear ask, it is probably FYI or filtered out.
|
||||
|
||||
### Step 6 — Write the reply starter
|
||||
|
||||
For High and Medium priority emails, write a one-sentence reply opener. The opener should:
|
||||
- Match the tone of the sender (formal vs. casual)
|
||||
- Acknowledge the ask directly
|
||||
- Be something the user can actually send with minimal editing
|
||||
|
||||
Example: "Thanks for flagging this — let me check with the team and get back to you by EOD."
|
||||
|
||||
If the email requires an action rather than a reply (e.g. "please approve this expense"), write: "No reply needed — action only: [describe the action]."
|
||||
|
||||
### Step 7 — Assemble and deliver the output
|
||||
|
||||
Use the output format exactly as specified. Do not add extra sections, editorialise, or explain your reasoning. The output should be scannable in under 60 seconds.
|
||||
|
||||
### Step 8 — Offer next steps
|
||||
|
||||
After the triage output, offer one of:
|
||||
- "Want me to draft replies to any of these?"
|
||||
- "Say 'reply to [name]' and I'll draft it."
|
||||
|
||||
Keep this to one line. Do not elaborate.
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] Time window was applied correctly — no emails outside the window are included
|
||||
- [ ] Gmail connector was confirmed active before reading
|
||||
- [ ] Every High Priority email has a specific, concrete "What they need" sentence — not a vague summary
|
||||
- [ ] Reply starters match the tone of the original email (formal/informal)
|
||||
- [ ] Filtered-out count is accurate and broken down by category
|
||||
- [ ] FYI section contains only emails with no action required — nothing actionable is buried here
|
||||
- [ ] Always-include senders surfaced regardless of category
|
||||
- [ ] Always-ignore senders/domains are fully suppressed
|
||||
- [ ] Output is scannable — no unnecessary prose, no padding
|
||||
- [ ] Financial statements and sensitive content were counted but not shown in full
|
||||
|
||||
## Dispatch / Mobile Usage
|
||||
|
||||
This skill works from the Claude mobile app (Dispatch). On mobile, the output renders cleanly with the emoji priority markers serving as visual anchors for quick scanning. Recommended mobile trigger: "Check my emails" or "/email-triage".
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- `/email-triage`
|
||||
- "Check my emails"
|
||||
- "What emails need my attention?"
|
||||
- "Triage my inbox for the last 8 hours"
|
||||
- "What came in since this morning?"
|
||||
- "Any urgent emails I need to deal with?"
|
||||
- "Triage my inbox — ignore anything from Jira and the marketing domain"
|
||||
- "Check emails from the last 24 hours, flag anything from [client name]"
|
||||
- "What do I need to reply to today?"
|
||||
@@ -0,0 +1,665 @@
|
||||
---
|
||||
name: instagram-post-downloader
|
||||
description: "Download Instagram posts — single images or full carousels — directly from a URL. Fetches high-resolution files from Instagram's CDN, saves them into a named folder, and stitches carousel slides into a single PDF. Supports batch downloading of multiple URLs at once. Use when asked to download, save, or archive an Instagram post, reel thumbnail, or carousel."
|
||||
---
|
||||
|
||||
# Instagram Post Downloader Skill
|
||||
|
||||
Downloads Instagram posts at full resolution from Instagram's CDN — no screenshots, no compression. Handles single images, carousels (multi-slide posts), and Reel cover images. For carousels, produces individual slide files plus a single stitched PDF. Supports batch URLs in one run.
|
||||
|
||||
---
|
||||
|
||||
## PREREQUISITE — Domain Allowlist
|
||||
|
||||
Before this skill can fetch any media, you must add Instagram's CDN domain to Claude Code's allowlist:
|
||||
|
||||
**Settings → Capabilities → Domain allowlist → Add:**
|
||||
```
|
||||
*.cdninstagram.com
|
||||
```
|
||||
|
||||
Without this, all CDN fetch calls will be blocked. If you see a permission error when Claude attempts a fetch to `cdninstagram.com`, this is the fix.
|
||||
|
||||
---
|
||||
|
||||
## Required Inputs
|
||||
|
||||
Claude will ask for these if not provided upfront:
|
||||
|
||||
| Input | Required | Notes |
|
||||
|---|---|---|
|
||||
| Instagram post URL(s) | Yes | One per line, or comma-separated. `https://www.instagram.com/p/XXXX/` or `https://www.instagram.com/reel/XXXX/` format |
|
||||
| Output directory | No | Defaults to `./instagram-downloads/` in the current working directory |
|
||||
| PDF stitch for carousels | No | Defaults to **yes** — produces `carousel.pdf` alongside individual slides |
|
||||
| File naming prefix | No | Optional prefix added before slide filenames, e.g. `brand_` → `brand_slide_01.jpg` |
|
||||
|
||||
**Batch input example:**
|
||||
```
|
||||
https://www.instagram.com/p/ABC123/
|
||||
https://www.instagram.com/p/DEF456/
|
||||
https://www.instagram.com/p/GHI789/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Output Structure
|
||||
|
||||
For each URL processed, Claude creates a folder named after the post caption (first 40 characters, sanitised — spaces become underscores, special characters stripped). If no caption is available, the folder is named after the post shortcode.
|
||||
|
||||
### Single image post
|
||||
|
||||
```
|
||||
instagram-downloads/
|
||||
└── this_is_the_caption_first_40_chars/
|
||||
├── image.jpg
|
||||
└── metadata.txt
|
||||
```
|
||||
|
||||
### Carousel post
|
||||
|
||||
```
|
||||
instagram-downloads/
|
||||
└── carousel_caption_first_40_chars/
|
||||
├── slide_01.jpg
|
||||
├── slide_02.jpg
|
||||
├── slide_03.jpg
|
||||
├── slide_04.jpg
|
||||
├── carousel.pdf ← all slides stitched in order
|
||||
└── metadata.txt
|
||||
```
|
||||
|
||||
### Batch run (3 URLs)
|
||||
|
||||
```
|
||||
instagram-downloads/
|
||||
├── first_post_caption_sanitised/
|
||||
│ ├── image.jpg
|
||||
│ └── metadata.txt
|
||||
├── second_post_carousel_caption/
|
||||
│ ├── slide_01.jpg
|
||||
│ ├── slide_02.jpg
|
||||
│ ├── carousel.pdf
|
||||
│ └── metadata.txt
|
||||
└── third_post_caption_here/
|
||||
├── image.jpg
|
||||
└── metadata.txt
|
||||
```
|
||||
|
||||
### metadata.txt format
|
||||
|
||||
```
|
||||
Post URL: https://www.instagram.com/p/XXXX/
|
||||
Shortcode: XXXX
|
||||
Type: carousel | single_image | reel
|
||||
Slide count: 4 (carousel only)
|
||||
Caption: [full caption text]
|
||||
Username: @username
|
||||
Fetched at: 2026-05-27T14:32:00Z
|
||||
CDN URLs:
|
||||
slide_01.jpg https://scontent.cdninstagram.com/v/...
|
||||
slide_02.jpg https://scontent.cdninstagram.com/v/...
|
||||
```
|
||||
|
||||
### Completion summary (printed to terminal)
|
||||
|
||||
```
|
||||
Instagram Post Downloader — Batch Complete
|
||||
==========================================
|
||||
URLs processed: 3
|
||||
Posts saved: 3
|
||||
Total files: 11 (9 images + 2 PDFs)
|
||||
Skipped: 0
|
||||
Output dir: /Users/you/project/instagram-downloads/
|
||||
|
||||
Results:
|
||||
✓ this_is_the_caption_first_40_chars/ 1 image
|
||||
✓ carousel_caption_first_40_chars/ 4 slides → carousel.pdf
|
||||
✓ third_post_caption_here/ 1 image
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## How Claude Should Execute This Skill
|
||||
|
||||
### Step 1 — Collect and validate inputs
|
||||
|
||||
1. Accept the URL(s) from the user. If the user pastes a comma-separated list, split on commas. If they paste one per line, split on newlines.
|
||||
2. Validate each URL matches `instagram.com/p/`, `instagram.com/reel/`, or `instagram.com/tv/`. Flag malformed URLs before proceeding.
|
||||
3. Confirm the output directory. If none provided, use `./instagram-downloads/` and tell the user.
|
||||
4. Ask about PDF stitching preference only if the user hasn't said either way. Default is yes.
|
||||
|
||||
### Step 2 — For each URL: fetch the post page
|
||||
|
||||
Fetch the Instagram post page HTML:
|
||||
|
||||
```
|
||||
GET https://www.instagram.com/p/{shortcode}/?__a=1&__d=dis
|
||||
```
|
||||
|
||||
Instagram frequently changes its API surface. Use this fallback chain in order:
|
||||
|
||||
**Attempt A — JSON endpoint:**
|
||||
```
|
||||
https://www.instagram.com/p/{shortcode}/?__a=1&__d=dis
|
||||
```
|
||||
Parse the JSON response. Look for `graphql.shortcode_media` or `data.shortcode_media`.
|
||||
|
||||
**Attempt B — Embed page (most reliable):**
|
||||
```
|
||||
https://www.instagram.com/p/{shortcode}/embed/captioned/
|
||||
```
|
||||
Fetch this page's HTML and extract `og:image` meta tags and any `window.__additionalDataLoaded` or `window.__StaticData` JSON blobs embedded in `<script>` tags.
|
||||
|
||||
**Attempt C — oEmbed endpoint:**
|
||||
```
|
||||
https://api.instagram.com/oembed/?url=https://www.instagram.com/p/{shortcode}/&omitscript=true
|
||||
```
|
||||
This returns `thumbnail_url` — useful for single images, but only gives the first frame for carousels.
|
||||
|
||||
**Headers to include on all requests:**
|
||||
```
|
||||
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36
|
||||
Accept-Language: en-US,en;q=0.9
|
||||
Accept: text/html,application/xhtml+xml,application/json
|
||||
```
|
||||
|
||||
### Step 3 — Extract CDN image URLs
|
||||
|
||||
From the fetched data, extract all high-resolution CDN URLs. Instagram CDN URLs follow these patterns:
|
||||
|
||||
```
|
||||
https://scontent.cdninstagram.com/v/...jpg?...
|
||||
https://scontent-lax3-1.cdninstagram.com/v/...jpg?...
|
||||
https://instagram.fXXX1-1.fbcdn.net/v/...jpg?...
|
||||
```
|
||||
|
||||
**For single image posts:**
|
||||
- Extract the single `display_url` or the largest `display_resources` entry (pick the one with the highest `config_width`).
|
||||
|
||||
**For carousel posts:**
|
||||
- Look for `edge_sidecar_to_children.edges[]` in the JSON. Each edge has its own `node.display_url` and `node.display_resources[]`.
|
||||
- Iterate all edges in order. This determines slide numbering.
|
||||
- Pick the highest-resolution variant from each slide's `display_resources` array.
|
||||
|
||||
**For Reels:**
|
||||
- The cover image is extractable the same way as a single image.
|
||||
- The video file itself requires a third-party tool (see Bonus section).
|
||||
|
||||
**If JSON extraction fails**, fall back to scraping `<meta property="og:image">` tags from the page HTML — this gives at least one image URL (the first slide or only image).
|
||||
|
||||
### Step 4 — Sanitise folder name
|
||||
|
||||
Build the folder name from the post caption:
|
||||
1. Take the first 40 characters of the caption.
|
||||
2. Strip all characters that are not alphanumeric, spaces, or hyphens.
|
||||
3. Replace spaces and hyphens with underscores.
|
||||
4. Lowercase the result.
|
||||
5. Strip leading/trailing underscores.
|
||||
6. If the result is empty (e.g. caption was all emoji), use the post shortcode instead.
|
||||
|
||||
```python
|
||||
import re
|
||||
|
||||
def sanitise_folder_name(caption: str, shortcode: str) -> str:
|
||||
truncated = caption[:40]
|
||||
cleaned = re.sub(r'[^a-zA-Z0-9 \-]', '', truncated)
|
||||
underscored = re.sub(r'[\s\-]+', '_', cleaned).strip('_').lower()
|
||||
return underscored if underscored else shortcode
|
||||
```
|
||||
|
||||
### Step 5 — Create output folder structure
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
base_dir = "./instagram-downloads"
|
||||
folder_name = sanitise_folder_name(caption, shortcode)
|
||||
post_dir = os.path.join(base_dir, folder_name)
|
||||
os.makedirs(post_dir, exist_ok=True)
|
||||
```
|
||||
|
||||
If a folder with that name already exists (e.g. running the same URL twice), append the shortcode to avoid collision: `folder_name_SHORTCODE`.
|
||||
|
||||
### Step 6 — Download each image file
|
||||
|
||||
For each CDN URL, download the file with a streaming GET request:
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
def download_file(url: str, dest_path: str) -> bool:
|
||||
headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
|
||||
"Referer": "https://www.instagram.com/",
|
||||
}
|
||||
response = requests.get(url, headers=headers, stream=True, timeout=30)
|
||||
response.raise_for_status()
|
||||
with open(dest_path, "wb") as f:
|
||||
for chunk in response.iter_content(chunk_size=8192):
|
||||
f.write(chunk)
|
||||
return True
|
||||
```
|
||||
|
||||
Name files:
|
||||
- Single image: `image.jpg`
|
||||
- Carousel slides: `slide_01.jpg`, `slide_02.jpg`, ... (zero-padded to 2 digits, or 3 digits if >99 slides)
|
||||
|
||||
Detect file format from the `Content-Type` header or URL extension. Instagram serves JPEG for photos and may serve WebP in some cases — preserve the actual extension.
|
||||
|
||||
### Step 7 — Stitch carousel PDF (if applicable)
|
||||
|
||||
After all slides are downloaded, stitch them into a single PDF using Pillow:
|
||||
|
||||
```python
|
||||
from PIL import Image
|
||||
|
||||
def stitch_to_pdf(image_paths: list[str], output_path: str) -> None:
|
||||
"""
|
||||
Combine a list of image files into a single multi-page PDF.
|
||||
Each image becomes one page. Page size matches the image dimensions.
|
||||
"""
|
||||
images = []
|
||||
for path in sorted(image_paths): # sort ensures slide_01, slide_02, ... order
|
||||
img = Image.open(path).convert("RGB")
|
||||
images.append(img)
|
||||
|
||||
if not images:
|
||||
return
|
||||
|
||||
first = images[0]
|
||||
rest = images[1:]
|
||||
first.save(
|
||||
output_path,
|
||||
format="PDF",
|
||||
save_all=True,
|
||||
append_images=rest,
|
||||
resolution=150.0,
|
||||
)
|
||||
```
|
||||
|
||||
Save as `carousel.pdf` in the post folder. If Pillow is not installed, run `pip install Pillow` first — or instruct the user to do so.
|
||||
|
||||
**Dependency check at start of skill:**
|
||||
```python
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
print("Pillow not installed. Run: pip install Pillow")
|
||||
print("PDF stitching will be skipped. Individual slides will still be downloaded.")
|
||||
skip_pdf = True
|
||||
```
|
||||
|
||||
### Step 8 — Write metadata.txt
|
||||
|
||||
Write a `metadata.txt` file into the post folder with all extracted metadata:
|
||||
|
||||
```python
|
||||
from datetime import datetime, timezone
|
||||
|
||||
def write_metadata(post_dir, post_url, shortcode, post_type, caption, username, cdn_urls):
|
||||
lines = [
|
||||
f"Post URL: {post_url}",
|
||||
f"Shortcode: {shortcode}",
|
||||
f"Type: {post_type}",
|
||||
]
|
||||
if post_type == "carousel":
|
||||
lines.append(f"Slide count: {len(cdn_urls)}")
|
||||
lines += [
|
||||
f"Caption: {caption}",
|
||||
f"Username: @{username}",
|
||||
f"Fetched at: {datetime.now(timezone.utc).isoformat()}",
|
||||
"CDN URLs:",
|
||||
]
|
||||
for filename, url in cdn_urls.items():
|
||||
lines.append(f" {filename:<16} {url}")
|
||||
|
||||
with open(os.path.join(post_dir, "metadata.txt"), "w", encoding="utf-8") as f:
|
||||
f.write("\n".join(lines) + "\n")
|
||||
```
|
||||
|
||||
### Step 9 — Print completion summary
|
||||
|
||||
After processing all URLs, print the summary table to the terminal (format shown in Output Structure section above). Include:
|
||||
- Total URLs attempted
|
||||
- Posts successfully saved
|
||||
- Total files written (images + PDFs separately)
|
||||
- Any URLs that were skipped and the reason
|
||||
|
||||
### Step 10 — Handle errors gracefully
|
||||
|
||||
| Error scenario | Action |
|
||||
|---|---|
|
||||
| URL is not an Instagram URL | Skip with message: "Skipped — not an Instagram URL: [url]" |
|
||||
| Post is private or requires login | Skip with message: "Skipped — post is private or login required: [url]" |
|
||||
| CDN fetch returns 403/404 | Try alternate CDN URL if available; if none, skip slide and note in metadata |
|
||||
| Pillow not installed | Skip PDF stitching, save slides only, note in summary |
|
||||
| Network timeout | Retry once after 5 seconds; if still failing, skip and log |
|
||||
| Folder name collision | Append shortcode suffix to folder name |
|
||||
| Rate limiting (429) | Wait 10 seconds and retry; log if retry also fails |
|
||||
|
||||
---
|
||||
|
||||
## Bonus — Downloading Instagram Reels (Video)
|
||||
|
||||
This skill covers images and carousel PDFs. For Reels video files, Claude Code cannot download video directly without a third-party tool, because Instagram's video CDN uses signed URLs and additional auth tokens.
|
||||
|
||||
**Recommended approach for Reels:**
|
||||
|
||||
Use `yt-dlp`, a maintained open-source tool:
|
||||
|
||||
```bash
|
||||
# Install
|
||||
pip install yt-dlp
|
||||
|
||||
# Download a Reel
|
||||
yt-dlp "https://www.instagram.com/reel/XXXX/" -o "%(title)s.%(ext)s"
|
||||
|
||||
# Download to a specific folder
|
||||
yt-dlp "https://www.instagram.com/reel/XXXX/" \
|
||||
-o "./instagram-downloads/%(uploader)s_%(id)s.%(ext)s"
|
||||
|
||||
# Download best quality
|
||||
yt-dlp -f "bestvideo+bestaudio" "https://www.instagram.com/reel/XXXX/"
|
||||
```
|
||||
|
||||
Claude can run this command via Bash if the user asks. `yt-dlp` handles the auth token extraction automatically for public Reels.
|
||||
|
||||
---
|
||||
|
||||
## Full Script Template
|
||||
|
||||
Claude should offer to write this as a standalone script (`instagram_downloader.py`) that the user can run independently:
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Instagram Post Downloader
|
||||
Fetches high-res images from public Instagram posts and carousels.
|
||||
Requires: pip install requests Pillow
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
import requests
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
PILLOW_AVAILABLE = True
|
||||
except ImportError:
|
||||
PILLOW_AVAILABLE = False
|
||||
print("Warning: Pillow not installed. PDF stitching disabled. Run: pip install Pillow")
|
||||
|
||||
|
||||
HEADERS = {
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 "
|
||||
"(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
||||
"Accept-Language": "en-US,en;q=0.9",
|
||||
"Referer": "https://www.instagram.com/",
|
||||
}
|
||||
|
||||
|
||||
def extract_shortcode(url: str) -> str:
|
||||
match = re.search(r"instagram\.com/(?:p|reel|tv)/([A-Za-z0-9_-]+)", url)
|
||||
if not match:
|
||||
raise ValueError(f"Cannot extract shortcode from URL: {url}")
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def fetch_post_data(shortcode: str) -> dict:
|
||||
"""Try multiple endpoints to get post JSON data."""
|
||||
# Attempt A: JSON endpoint
|
||||
try:
|
||||
url = f"https://www.instagram.com/p/{shortcode}/?__a=1&__d=dis"
|
||||
r = requests.get(url, headers=HEADERS, timeout=15)
|
||||
if r.status_code == 200:
|
||||
data = r.json()
|
||||
media = (data.get("graphql", {}).get("shortcode_media") or
|
||||
data.get("data", {}).get("shortcode_media"))
|
||||
if media:
|
||||
return media
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Attempt B: Embed page
|
||||
try:
|
||||
url = f"https://www.instagram.com/p/{shortcode}/embed/captioned/"
|
||||
r = requests.get(url, headers=HEADERS, timeout=15)
|
||||
html = r.text
|
||||
# Look for JSON blob in script tags
|
||||
matches = re.findall(r'window\.__additionalDataLoaded\([^,]+,(\{.+?\})\);', html)
|
||||
for blob in matches:
|
||||
try:
|
||||
data = json.loads(blob)
|
||||
media = (data.get("graphql", {}).get("shortcode_media") or
|
||||
data.get("data", {}).get("shortcode_media"))
|
||||
if media:
|
||||
return media
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return {}
|
||||
|
||||
|
||||
def get_cdn_urls(media: dict) -> list[tuple[str, str]]:
|
||||
"""Return list of (filename, cdn_url) tuples."""
|
||||
results = []
|
||||
media_type = media.get("__typename", "")
|
||||
|
||||
if media_type == "GraphSidecar":
|
||||
edges = media.get("edge_sidecar_to_children", {}).get("edges", [])
|
||||
for i, edge in enumerate(edges, start=1):
|
||||
node = edge.get("node", {})
|
||||
resources = node.get("display_resources", [])
|
||||
url = (max(resources, key=lambda r: r.get("config_width", 0)).get("src")
|
||||
if resources else node.get("display_url", ""))
|
||||
if url:
|
||||
ext = "jpg" if "jpg" in url.lower() else "webp"
|
||||
filename = f"slide_{i:02d}.{ext}"
|
||||
results.append((filename, url))
|
||||
else:
|
||||
resources = media.get("display_resources", [])
|
||||
url = (max(resources, key=lambda r: r.get("config_width", 0)).get("src")
|
||||
if resources else media.get("display_url", ""))
|
||||
if url:
|
||||
ext = "jpg" if "jpg" in url.lower() else "webp"
|
||||
results.append((f"image.{ext}", url))
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def sanitise_folder_name(caption: str, shortcode: str) -> str:
|
||||
truncated = caption[:40] if caption else ""
|
||||
cleaned = re.sub(r"[^a-zA-Z0-9 \-]", "", truncated)
|
||||
underscored = re.sub(r"[\s\-]+", "_", cleaned).strip("_").lower()
|
||||
return underscored if underscored else shortcode
|
||||
|
||||
|
||||
def download_file(url: str, dest_path: str) -> bool:
|
||||
r = requests.get(url, headers=HEADERS, stream=True, timeout=30)
|
||||
r.raise_for_status()
|
||||
with open(dest_path, "wb") as f:
|
||||
for chunk in r.iter_content(chunk_size=8192):
|
||||
f.write(chunk)
|
||||
return True
|
||||
|
||||
|
||||
def stitch_pdf(image_paths: list[str], output_path: str) -> None:
|
||||
if not PILLOW_AVAILABLE:
|
||||
return
|
||||
images = [Image.open(p).convert("RGB") for p in sorted(image_paths)]
|
||||
if images:
|
||||
images[0].save(output_path, format="PDF", save_all=True,
|
||||
append_images=images[1:], resolution=150.0)
|
||||
|
||||
|
||||
def process_url(post_url: str, base_dir: str, stitch_pdf_flag: bool) -> dict:
|
||||
result = {"url": post_url, "status": "ok", "files": [], "error": None}
|
||||
try:
|
||||
shortcode = extract_shortcode(post_url)
|
||||
media = fetch_post_data(shortcode)
|
||||
|
||||
caption = ""
|
||||
username = ""
|
||||
if media:
|
||||
caption_edges = media.get("edge_media_to_caption", {}).get("edges", [])
|
||||
caption = caption_edges[0]["node"]["text"] if caption_edges else ""
|
||||
owner = media.get("owner", {})
|
||||
username = owner.get("username", "")
|
||||
|
||||
folder_name = sanitise_folder_name(caption, shortcode)
|
||||
post_dir = os.path.join(base_dir, folder_name)
|
||||
if os.path.exists(post_dir):
|
||||
post_dir = f"{post_dir}_{shortcode}"
|
||||
os.makedirs(post_dir, exist_ok=True)
|
||||
|
||||
cdn_urls = get_cdn_urls(media) if media else []
|
||||
if not cdn_urls:
|
||||
# Fallback: oEmbed
|
||||
oembed_url = f"https://api.instagram.com/oembed/?url={post_url}&omitscript=true"
|
||||
r = requests.get(oembed_url, headers=HEADERS, timeout=10)
|
||||
if r.status_code == 200:
|
||||
thumb = r.json().get("thumbnail_url", "")
|
||||
if thumb:
|
||||
cdn_urls = [("image.jpg", thumb)]
|
||||
username = r.json().get("author_name", "")
|
||||
|
||||
downloaded_paths = []
|
||||
cdn_map = {}
|
||||
for filename, url in cdn_urls:
|
||||
dest = os.path.join(post_dir, filename)
|
||||
download_file(url, dest)
|
||||
downloaded_paths.append(dest)
|
||||
cdn_map[filename] = url
|
||||
result["files"].append(filename)
|
||||
|
||||
if stitch_pdf_flag and len(downloaded_paths) > 1 and PILLOW_AVAILABLE:
|
||||
pdf_path = os.path.join(post_dir, "carousel.pdf")
|
||||
stitch_pdf(downloaded_paths, pdf_path)
|
||||
result["files"].append("carousel.pdf")
|
||||
|
||||
post_type = "carousel" if len(cdn_urls) > 1 else "single_image"
|
||||
write_metadata(post_dir, post_url, shortcode, post_type, caption, username, cdn_map)
|
||||
result["files"].append("metadata.txt")
|
||||
|
||||
except Exception as e:
|
||||
result["status"] = "error"
|
||||
result["error"] = str(e)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def write_metadata(post_dir, post_url, shortcode, post_type, caption, username, cdn_map):
|
||||
lines = [
|
||||
f"Post URL: {post_url}",
|
||||
f"Shortcode: {shortcode}",
|
||||
f"Type: {post_type}",
|
||||
]
|
||||
if post_type == "carousel":
|
||||
lines.append(f"Slide count: {len([k for k in cdn_map if 'slide' in k])}")
|
||||
lines += [
|
||||
f"Caption: {caption}",
|
||||
f"Username: @{username}",
|
||||
f"Fetched at: {datetime.now(timezone.utc).isoformat()}",
|
||||
"CDN URLs:",
|
||||
]
|
||||
for fn, url in cdn_map.items():
|
||||
lines.append(f" {fn:<18} {url}")
|
||||
with open(os.path.join(post_dir, "metadata.txt"), "w", encoding="utf-8") as f:
|
||||
f.write("\n".join(lines) + "\n")
|
||||
|
||||
|
||||
def main(urls: list[str], base_dir: str = "./instagram-downloads", stitch: bool = True):
|
||||
os.makedirs(base_dir, exist_ok=True)
|
||||
results = []
|
||||
for url in urls:
|
||||
url = url.strip()
|
||||
if not url:
|
||||
continue
|
||||
print(f"Processing: {url}")
|
||||
r = process_url(url, base_dir, stitch)
|
||||
results.append(r)
|
||||
time.sleep(1) # polite delay between requests
|
||||
|
||||
# Summary
|
||||
ok = [r for r in results if r["status"] == "ok"]
|
||||
err = [r for r in results if r["status"] == "error"]
|
||||
total_files = sum(len(r["files"]) for r in ok)
|
||||
print("\nInstagram Post Downloader — Batch Complete")
|
||||
print("==========================================")
|
||||
print(f"URLs processed: {len(results)}")
|
||||
print(f"Posts saved: {len(ok)}")
|
||||
print(f"Total files: {total_files}")
|
||||
print(f"Errors: {len(err)}")
|
||||
print(f"Output dir: {os.path.abspath(base_dir)}\n")
|
||||
for r in results:
|
||||
if r["status"] == "ok":
|
||||
print(f" OK {r['url']}")
|
||||
else:
|
||||
print(f" ERR {r['url']} — {r['error']}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python instagram_downloader.py <url1> [url2] ...")
|
||||
sys.exit(1)
|
||||
main(sys.argv[1:])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quality Checks
|
||||
|
||||
Before marking the task complete, verify each item:
|
||||
|
||||
- [ ] Domain allowlist confirmed — `*.cdninstagram.com` is added before any fetch attempts
|
||||
- [ ] All provided URLs validated as Instagram URLs before processing begins
|
||||
- [ ] CDN URLs are the highest-resolution variants available (largest `config_width` selected)
|
||||
- [ ] Folder name is sanitised — no special characters, no spaces, max 40 chars from caption
|
||||
- [ ] Folder collision handled — shortcode appended if folder already exists
|
||||
- [ ] Carousel slides numbered sequentially with zero-padding (`slide_01`, `slide_02`, ...)
|
||||
- [ ] PDF includes all slides in correct order (not alphabetical — by slide index)
|
||||
- [ ] metadata.txt written to every post folder, including full CDN URLs
|
||||
- [ ] Pillow dependency checked at startup — graceful fallback if not available
|
||||
- [ ] Batch completion summary printed with file counts and any errors
|
||||
- [ ] Private post errors caught and reported — not silently skipped
|
||||
- [ ] Rate limiting handled — at least 1 second delay between requests
|
||||
- [ ] No credential or cookie storage — skill operates on public posts only
|
||||
|
||||
---
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "Download this Instagram post for me: https://www.instagram.com/p/ABC123/"
|
||||
- "Save that carousel to my downloads folder"
|
||||
- "Can you grab all the slides from this Instagram post and make a PDF?"
|
||||
- "Download these 5 Instagram posts" [followed by list of URLs]
|
||||
- "Archive this IG post before it gets deleted"
|
||||
- "I need the full-res images from this carousel"
|
||||
- "Download the images from this Instagram URL and stitch them into a PDF"
|
||||
- "Batch download these Instagram posts" [followed by URLs]
|
||||
- "Save the slides from this Instagram carousel as individual JPEGs"
|
||||
- "Get me the high-res version of this Instagram image"
|
||||
|
||||
---
|
||||
|
||||
## Notes on Instagram's Anti-Scraping Measures
|
||||
|
||||
Instagram actively changes its page structure and API endpoints. If all three fetch attempts fail:
|
||||
|
||||
1. The embed page method (`/embed/captioned/`) is historically the most stable — start there.
|
||||
2. CDN URLs expire. Download immediately after fetching — do not store URLs and download later.
|
||||
3. Instagram may return a login wall for some posts even if they're technically public. If this happens, the skill cannot proceed without authentication (which is out of scope).
|
||||
4. If Instagram returns a 429, wait 10–30 seconds before retrying. Reduce batch size for large lists.
|
||||
|
||||
This skill is designed for public posts only. It does not support login, sessions, or private content.
|
||||
|
||||
---
|
||||
|
||||
*Originally inspired by a skill from Frank and Diana Dovgopol (Write, Prompt, Scale) — adapted and extended for this library.*
|
||||
@@ -0,0 +1,150 @@
|
||||
---
|
||||
name: last-30-days-research
|
||||
description: Multi-platform research skill that gathers recent (last 30 days) opinions, sentiment, and signal on any topic from Reddit, X/Twitter, and the web. Cuts through SEO-stuffed results to surface what real people are actually saying.
|
||||
---
|
||||
|
||||
# Last 30 Days Research
|
||||
|
||||
## The Problem
|
||||
|
||||
Googling gives SEO-stuffed "best of" lists written six months ago by someone who has never used the thing. Real honest takes live on Reddit threads, X replies, and niche communities — but chasing them across platforms eats your afternoon. This skill does the chase for you.
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Required | Notes |
|
||||
|-------|----------|-------|
|
||||
| Topic | Yes | Tool, trend, feature, product, event, company — anything with a name |
|
||||
| Date scope | No | Defaults to last 30 days. Can override to last 7 days or last 90 days |
|
||||
| Angle | No | e.g. "focus on developer sentiment" or "looking for pricing complaints specifically" |
|
||||
|
||||
## Output Structure
|
||||
|
||||
The output is a structured research report with the following sections, delivered in this exact order:
|
||||
|
||||
```
|
||||
## Last 30 Days Research: [Topic]
|
||||
Research window: [Date 30 days ago] → [Today's date]
|
||||
|
||||
---
|
||||
|
||||
## What People Agree On
|
||||
[Consensus points that appear across multiple platforms — most reliable signal]
|
||||
|
||||
## Where People Disagree
|
||||
[Active debates, contrasting views — include which side has more weight]
|
||||
|
||||
## Pain Points That Keep Coming Up
|
||||
[Recurring complaints and frustrations — strongest signal of real problems]
|
||||
|
||||
## Positive Signals
|
||||
[What people genuinely praise — not PR, but unprompted appreciation]
|
||||
|
||||
## Most Interesting Takes
|
||||
[Contrarian, unexpected, or surprisingly insightful comments worth noting]
|
||||
|
||||
## Sources
|
||||
[Links to the most useful threads/posts found — 5–10 links with brief labels]
|
||||
|
||||
## Signal Confidence
|
||||
[High / Medium / Low — with a one-line rationale based on data volume and consistency]
|
||||
```
|
||||
|
||||
Each section should contain substantive content, not placeholders. If a section has no findings (e.g. no positive signals found), state that explicitly rather than leaving it empty or fabricating content.
|
||||
|
||||
## Instructions for Claude
|
||||
|
||||
### Step 1 — Calculate the date window
|
||||
|
||||
Determine today's date and subtract 30 days to get the research start date. Format: YYYY-MM-DD. Use these dates explicitly in every search query.
|
||||
|
||||
### Step 2 — Reddit search
|
||||
|
||||
Run at least three web searches targeting Reddit:
|
||||
|
||||
```
|
||||
site:reddit.com "[topic]" after:[30-days-ago-date]
|
||||
site:reddit.com "[topic]" 2025
|
||||
reddit.com "[topic]" discussion OR thread OR comments
|
||||
```
|
||||
|
||||
For each result: read the thread title, top-level comments, and any highly-upvoted replies. Record the key claims and the URL.
|
||||
|
||||
If the topic has common synonyms or abbreviations, run additional searches with those (e.g. "Claude Code" and "claude.code" and "Anthropic coding tool").
|
||||
|
||||
### Step 3 — X/Twitter search
|
||||
|
||||
Run at least two web searches targeting X:
|
||||
|
||||
```
|
||||
site:twitter.com OR site:x.com "[topic]" after:[30-days-ago-date]
|
||||
"[topic]" site:x.com -is:retweet
|
||||
```
|
||||
|
||||
Note: X search via web has limitations. If results are sparse, supplement with searches for specific accounts known to discuss the topic area (e.g. tech journalists, domain experts).
|
||||
|
||||
### Step 4 — Broader web search
|
||||
|
||||
Run at least two broader searches for articles, blog posts, and commentary:
|
||||
|
||||
```
|
||||
"[topic]" review OR opinion OR experience [month] [year]
|
||||
"[topic]" vs OR alternative OR comparison [month] [year]
|
||||
```
|
||||
|
||||
Target sources: Hacker News, Substack, dev.to, personal blogs, product communities. Avoid press releases and vendor-authored content.
|
||||
|
||||
### Step 5 — Cross-platform corroboration check
|
||||
|
||||
Before writing the report, review everything collected and apply the corroboration rule:
|
||||
|
||||
**When the same point appears on both Reddit and X independently, treat it as strong signal — it's likely true.**
|
||||
|
||||
A point mentioned only once on one platform is a data point, not a finding. Weight your sections accordingly.
|
||||
|
||||
### Step 6 — Write the report
|
||||
|
||||
Populate each section of the output structure. Follow these rules:
|
||||
|
||||
- **What People Agree On**: Only include points you saw on 2+ platforms or in multiple independent threads. These are your most reliable findings.
|
||||
- **Where People Disagree**: Name the sides. "Some say X, others say Y — and the X camp seems louder based on upvote counts / engagement."
|
||||
- **Pain Points**: Be specific. "Performance issues" is weak. "Cold start times over 4 seconds on the free tier" is useful.
|
||||
- **Positive Signals**: Must be unprompted praise, not from product marketing or sponsored content.
|
||||
- **Most Interesting Takes**: At least 2, maximum 5. Quote or closely paraphrase where possible.
|
||||
- **Sources**: Include the actual URLs. Label each one briefly (e.g. "Reddit thread: 'Has anyone switched from X to Y?'").
|
||||
- **Signal Confidence**: Rate High/Medium/Low based on:
|
||||
- High = 10+ sources, consistent signal across platforms
|
||||
- Medium = 5–10 sources, some inconsistency
|
||||
- Low = fewer than 5 sources, or highly fragmented signal
|
||||
|
||||
### Step 7 — Sanity check before delivering
|
||||
|
||||
Before outputting the report, verify:
|
||||
|
||||
- [ ] Every claim in the report traces to an actual source found during research (not prior knowledge)
|
||||
- [ ] The date window was actually applied to searches, not ignored
|
||||
- [ ] No fabricated or hallucinated URLs in the Sources section
|
||||
- [ ] Signal Confidence rating reflects the actual data volume, not optimism
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] At minimum 3 Reddit searches were run with the date filter applied
|
||||
- [ ] At minimum 2 X/Twitter searches were run
|
||||
- [ ] At minimum 2 broader web searches were run
|
||||
- [ ] Cross-platform corroboration principle was applied (same point on multiple platforms = stronger signal)
|
||||
- [ ] Pain Points section contains specific, concrete details — not vague generalisations
|
||||
- [ ] Sources section contains real URLs (not hallucinated), verified during research
|
||||
- [ ] Signal Confidence is rated and justified
|
||||
- [ ] If a section has no findings, it says so explicitly rather than being omitted or padded
|
||||
- [ ] No vendor-authored content or press releases treated as independent signal
|
||||
- [ ] Synonyms and alternative names for the topic were searched
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "What are people saying about Cursor AI from the last 30 days?"
|
||||
- "Research Vercel's recent sentiment"
|
||||
- "Last 30 days on the Arc browser shutdown"
|
||||
- "What's the current vibe on Supabase?"
|
||||
- "What are developers saying about Claude Code lately?"
|
||||
- "Research [topic] from the last 30 days"
|
||||
- "Give me a signal report on [product]"
|
||||
- "What's the Reddit and Twitter take on [trend]?"
|
||||
@@ -0,0 +1,198 @@
|
||||
---
|
||||
name: morning-intelligence
|
||||
description: "Run a 15-question interview to capture your role, topics, sources, exclusions, and format preferences — then write a master prompt you can drop into a scheduled task or Claude Code Routine to get a personalised news brief every morning. Use when asked to set up a morning intelligence brief, build a morning news prompt, or create a personalised news briefing."
|
||||
---
|
||||
|
||||
# Morning Intelligence Skill
|
||||
|
||||
Write the prompt that writes your briefing. A 15-question interview extracts your exact context — role, topics, sources, exclusions, format, recency — then produces a single master prompt you can paste into a scheduled task or Claude Code Routine and never touch again.
|
||||
|
||||
> **Pro tip:** Run this interview with Opus for the best output. Opus asks sharper follow-up questions and writes a tighter master prompt.
|
||||
|
||||
> **Credit:** Originally created by Ashwin Francis (Cash&Cache) — adapted and extended for this library.
|
||||
|
||||
---
|
||||
|
||||
## Required Inputs
|
||||
|
||||
No inputs required upfront. The skill runs the interview first.
|
||||
|
||||
If the user has already provided context (e.g. pasted a role description or topic list), absorb it and skip those questions in the interview — don't ask for information already given.
|
||||
|
||||
---
|
||||
|
||||
## How the Interview Works
|
||||
|
||||
Run questions **one at a time** (or in small groups of 2–3 where they're closely related). Don't dump all 15 at once. Wait for each answer before proceeding. Ask natural follow-ups where the answer is vague.
|
||||
|
||||
### Interview Questions
|
||||
|
||||
**Block 1 — Who you are and how you read**
|
||||
|
||||
1. What is your role, and what lens do you read news through? (e.g. "Head of Product at a B2B SaaS — I read for competitive moves, AI tooling, and enterprise buying signals.")
|
||||
2. What are the 3–5 topics you always want covered? Be specific — "AI" is too broad; "AI applied to enterprise software" is better.
|
||||
3. What are 2–3 topics you actively want filtered out — things that waste your time every morning?
|
||||
|
||||
**Block 2 — Sources and signals**
|
||||
|
||||
4. Which publications, newsletters, or outlets do you trust most? (Examples: The Information, TLDR, Benedict Evans, Stratechery, FT, specific subreddits)
|
||||
5. Are there any Twitter/X accounts, Substack writers, or niche sources that are must-reads for you specifically?
|
||||
6. Is there any geography that matters — are you focused on a specific country, region, or market?
|
||||
|
||||
**Block 3 — Story type and recency**
|
||||
|
||||
7. What mix of story types do you want? Rank or weight these: breaking news / in-depth analysis / opinion / data & research / product launches & announcements.
|
||||
8. How fresh does the content need to be? Only today's news? Last 24 hours? Last 48 hours? Or are you okay with "last few days" if a story is important enough?
|
||||
|
||||
**Block 4 — Format and time**
|
||||
|
||||
9. How do you want the brief formatted? Options: bullet list by topic / short narrative paragraphs / a digest with headlines + 1-line summaries / a table / mixed.
|
||||
10. What's your reading time budget in the morning? 5 minutes (tight digest) / 10 minutes (fuller brief) / 15 minutes (comprehensive).
|
||||
|
||||
**Block 5 — This week specifically**
|
||||
|
||||
11. Is there anything you're tracking this week in particular — a specific company, deal, product launch, regulatory development, or ongoing story?
|
||||
|
||||
**Block 6 — Follow-up clarification (questions 12–15)**
|
||||
|
||||
Based on the answers above, ask 4 targeted follow-up questions to sharpen ambiguities. Examples of what to probe:
|
||||
|
||||
- If a topic is still broad: "You said [topic] — do you want the technical angle, the business/market angle, or both?"
|
||||
- If sources are vague: "When you say [publication], do you want everything from them or only specific sections/writers?"
|
||||
- If format is unclear: "You want bullets — should each topic have its own section with 3–5 bullets, or one flat list of all stories?"
|
||||
- If recency conflicts with format: "You want only today's news but a comprehensive 15-minute brief — on slow news days, should I go deeper on one story or pull from the last 48 hours to fill it out?"
|
||||
- If exclusions are vague: "You said no [topic] — does that include adjacent topics like [related thing], or strictly [topic]?"
|
||||
|
||||
Use your judgement on which 4 are most worth asking given the actual answers.
|
||||
|
||||
---
|
||||
|
||||
## Output Structure
|
||||
|
||||
After the interview is complete, produce three things in order:
|
||||
|
||||
### 1. Summary of What You Told Me
|
||||
|
||||
A brief summary of the interview, clustered into thematic pillars. This lets the user verify the master prompt will be accurate before it's written.
|
||||
|
||||
```
|
||||
WHAT I HEARD
|
||||
────────────
|
||||
Role lens: [1 sentence]
|
||||
Core topics: [Pillar 1] · [Pillar 2] · [Pillar 3]
|
||||
Exclusions: [Topic A], [Topic B]
|
||||
Sources: [List]
|
||||
Story mix: [e.g. 60% analysis, 30% news, 10% data]
|
||||
Recency: [e.g. Last 24 hours, today only for breaking]
|
||||
Format: [e.g. Bullets by topic, ~10 min read]
|
||||
This week: [Specific tracking items]
|
||||
```
|
||||
|
||||
Confirm: "Does this look right? I'll write the master prompt based on this."
|
||||
|
||||
---
|
||||
|
||||
### 2. The Master Prompt
|
||||
|
||||
Formatted and ready to paste. Start with a markdown code block so the user can copy it cleanly.
|
||||
|
||||
````
|
||||
```
|
||||
MORNING INTELLIGENCE BRIEF — MASTER PROMPT
|
||||
==========================================
|
||||
|
||||
You are an intelligence analyst briefing [ROLE] at the start of their day.
|
||||
|
||||
TASK
|
||||
Generate a personalised morning news brief covering the following.
|
||||
|
||||
TOPICS TO COVER
|
||||
1. [Topic / Pillar 1] — focus on [angle]
|
||||
2. [Topic / Pillar 2] — focus on [angle]
|
||||
3. [Topic / Pillar 3] — focus on [angle]
|
||||
[add pillars as needed]
|
||||
|
||||
NEVER INCLUDE
|
||||
- [Excluded topic 1]
|
||||
- [Excluded topic 2]
|
||||
- [Excluded topic 3]
|
||||
|
||||
PREFERRED SOURCES (prioritise these)
|
||||
[Source 1], [Source 2], [Source 3], [Source 4]
|
||||
|
||||
STORY TYPE MIX
|
||||
[e.g. Prioritise analysis and data-driven pieces. Include breaking news only if significant. Skip opinion unless it's from [specific writer].]
|
||||
|
||||
RECENCY
|
||||
[e.g. Cover only the last 24 hours. For ongoing stories I'm tracking, include relevant developments from the last 48 hours.]
|
||||
|
||||
CURRENTLY TRACKING THIS WEEK
|
||||
[Specific story / company / topic the user flagged]
|
||||
|
||||
FORMAT
|
||||
[e.g. Organise by topic. Under each topic: 2–4 bullet points. Each bullet: headline + 1–2 sentence summary + source name. End with a "What to watch today" section: 2–3 sentences on what matters most today.]
|
||||
|
||||
LENGTH
|
||||
Target a [5/10/15]-minute read.
|
||||
|
||||
TONE
|
||||
Analyst voice. No fluff. Lead with the signal, not the noise. If something is uncertain or based on incomplete reporting, flag it as such.
|
||||
```
|
||||
````
|
||||
|
||||
---
|
||||
|
||||
### 3. Setup Guide
|
||||
|
||||
A short section below the master prompt:
|
||||
|
||||
```
|
||||
HOW TO USE THIS PROMPT
|
||||
──────────────────────
|
||||
|
||||
OPTION A — Cowork Scheduled Tasks (Claude Pro/Max)
|
||||
Requires: Desktop app open at scheduled time
|
||||
1. Open Claude desktop → Cowork → Scheduled Tasks
|
||||
2. Create a new task, set your time (e.g. 7:00 AM)
|
||||
3. Paste the master prompt as the task content
|
||||
4. Save. It will run every morning when your desktop app is open.
|
||||
|
||||
OPTION B — Claude Code Routines (runs in the cloud)
|
||||
Requires: Claude Code with Routines access
|
||||
Advantage: Runs without your laptop being on
|
||||
1. In your project root, create or open .claude/routines.json
|
||||
2. Add a new routine with a cron schedule (e.g. "0 7 * * *" for 7 AM daily)
|
||||
3. Set the prompt field to the master prompt above
|
||||
4. Commit and push — Claude Code will run it on schedule.
|
||||
|
||||
UPDATING YOUR BRIEF
|
||||
When your focus shifts, re-run this skill. The interview takes 5–10 minutes
|
||||
and produces a new master prompt to replace the old one.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] Every interview question was asked — none skipped unless the user already provided the answer
|
||||
- [ ] The "What I Heard" summary was shown and confirmed before writing the master prompt
|
||||
- [ ] The master prompt uses specific topic angles, not vague category names (not "AI" — "AI applied to enterprise software")
|
||||
- [ ] Exclusions are explicitly stated in the master prompt with a NEVER INCLUDE section
|
||||
- [ ] Sources are listed in order of preference, not as a flat unordered list
|
||||
- [ ] Story type mix is written as a directive, not just a list
|
||||
- [ ] Recency instruction handles the edge case of slow news days
|
||||
- [ ] Format instruction is precise enough that a different AI could follow it correctly
|
||||
- [ ] The master prompt is inside a code block so it copies cleanly
|
||||
- [ ] Both setup options (Cowork and Claude Code Routines) are included
|
||||
|
||||
---
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "Set up my morning intelligence brief"
|
||||
- "Build me a morning news prompt"
|
||||
- "Interview me for a morning briefing skill"
|
||||
- "I want to start every day with a personalised news digest"
|
||||
- "Help me set up a daily AI news brief"
|
||||
- "Create a scheduled morning news prompt for me"
|
||||
- "Build me a prompt for my daily briefing routine"
|
||||
@@ -0,0 +1,175 @@
|
||||
---
|
||||
name: notebooklm-connector
|
||||
description: Automates NotebookLM from Claude Code — creates notebooks, adds sources, and triggers outputs (mindmaps, audio overviews, slide decks) without manual clicking via the Claude Chrome extension.
|
||||
---
|
||||
|
||||
# NotebookLM Connector
|
||||
|
||||
## The Problem
|
||||
|
||||
NotebookLM is one of the best AI research tools — but it doesn't connect to your other tools. Every notebook requires manual setup inside the NotebookLM UI: open browser, name the notebook, paste URLs one by one, click generate. For researchers, builders, or anyone who works with a high volume of sources, this friction compounds fast.
|
||||
|
||||
This skill automates NotebookLM from Claude Code using browser automation via the Claude Chrome extension.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
| Requirement | Details |
|
||||
|-------------|---------|
|
||||
| Claude Chrome extension | Must be installed and active in your Chrome browser |
|
||||
| NotebookLM account | Active account at notebooklm.google.com |
|
||||
| Chrome browser | Open and signed into NotebookLM |
|
||||
|
||||
If the Chrome extension is not installed, this skill cannot function. There is no fallback — you will need to perform actions manually.
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Required | Notes |
|
||||
|-------|----------|-------|
|
||||
| Action(s) to perform | Yes | What you want done — see Supported Actions below |
|
||||
| Notebook name | Conditional | Required for create; optional for add/generate if a notebook is already open |
|
||||
| Sources | Conditional | Required for add sources action — URLs, file paths, or pasted text |
|
||||
| Output type | Conditional | Required for generate action — mindmap, audio overview, or briefing doc |
|
||||
|
||||
## Supported Actions
|
||||
|
||||
| Action | What It Does |
|
||||
|--------|-------------|
|
||||
| Create notebook | Opens NotebookLM, creates a new notebook with the specified title |
|
||||
| Add sources | Adds one or more URLs, files, or text blocks as sources to a notebook |
|
||||
| Generate mindmap | Triggers mindmap generation from the notebook's sources |
|
||||
| Generate audio overview | Requests an audio overview (note: takes several minutes to render) |
|
||||
| Generate briefing doc | Requests a briefing document or slide deck from sources |
|
||||
| List notebooks | Lists your existing notebooks and their source counts |
|
||||
| Open notebook | Navigates to a specific existing notebook by name |
|
||||
|
||||
Actions can be chained in a single request: "Create a notebook called 'AI Trends Q2', add these 3 URLs as sources, then generate a mindmap."
|
||||
|
||||
## Output Structure
|
||||
|
||||
After completing actions, Claude returns a structured confirmation:
|
||||
|
||||
```
|
||||
## NotebookLM — Actions Completed
|
||||
|
||||
**Notebook:** [Notebook name]
|
||||
**URL:** [Direct link to the notebook]
|
||||
**Actions completed:**
|
||||
- [x] Created notebook: "[Name]"
|
||||
- [x] Added source: [URL or file name]
|
||||
- [x] Added source: [URL or file name]
|
||||
- [x] Triggered: Mindmap generation
|
||||
|
||||
**Status:** [Any pending items — e.g. "Audio overview is generating, check back in 5–10 minutes"]
|
||||
|
||||
**Notes:** [Any issues encountered or deviations from the requested actions]
|
||||
```
|
||||
|
||||
If an action fails, the failed step is marked with `[ ]` and a reason is provided. See Error Handling below.
|
||||
|
||||
## Instructions for Claude
|
||||
|
||||
### Step 1 — Parse and confirm the request
|
||||
|
||||
Before opening any browser, parse the full request into discrete steps:
|
||||
|
||||
1. What notebook is being targeted (new or existing)?
|
||||
2. What sources need to be added (list each URL or file)?
|
||||
3. What outputs need to be generated?
|
||||
|
||||
If anything is ambiguous — e.g. "add my research sources" without specifying what they are — ask for clarification before proceeding. Do not guess at source URLs.
|
||||
|
||||
### Step 2 — Check the Chrome extension is available
|
||||
|
||||
Confirm browser automation is available via the Claude Chrome extension. If it is not active, stop and report:
|
||||
|
||||
> "This skill requires the Claude Chrome extension to be installed and active. Please install it at [extension URL] and try again."
|
||||
|
||||
### Step 3 — Navigate to NotebookLM
|
||||
|
||||
Open or navigate to `https://notebooklm.google.com`. Confirm the user is logged in. If a login screen appears, stop and ask the user to log in manually, then retry.
|
||||
|
||||
### Step 4 — Execute actions in order
|
||||
|
||||
Execute each action in the sequence requested. After each action, confirm it completed before moving to the next. Do not batch actions speculatively.
|
||||
|
||||
**Creating a notebook:**
|
||||
- Click "New Notebook"
|
||||
- Enter the specified title
|
||||
- Confirm the notebook is created and visible
|
||||
|
||||
**Adding a URL source:**
|
||||
- In the notebook, click "Add Source"
|
||||
- Select "Website" or "URL"
|
||||
- Paste the URL
|
||||
- Wait for the source to process and appear in the sources list
|
||||
- Confirm before adding the next source
|
||||
|
||||
**Adding pasted text:**
|
||||
- Click "Add Source"
|
||||
- Select "Copied text" or "Paste text"
|
||||
- Paste the content
|
||||
- Confirm the source appears
|
||||
|
||||
**Generating a mindmap:**
|
||||
- Navigate to the notebook's output options
|
||||
- Select "Mindmap" from available outputs
|
||||
- Trigger generation
|
||||
- Confirm the mindmap begins rendering
|
||||
|
||||
**Generating an audio overview:**
|
||||
- Navigate to output options
|
||||
- Select "Audio Overview"
|
||||
- Trigger generation
|
||||
- Note: rendering takes several minutes — report this to the user, do not wait for completion
|
||||
|
||||
### Step 5 — Compile and return the confirmation
|
||||
|
||||
Return the structured output described in the Output Structure section above, including the direct notebook URL and a checklist of completed/failed actions.
|
||||
|
||||
## Error Handling
|
||||
|
||||
If any step fails, do the following:
|
||||
|
||||
1. Stop at the failed step (do not attempt to continue)
|
||||
2. Report the exact step that failed and what was observed
|
||||
3. Suggest a manual workaround for that step
|
||||
4. Offer to retry from that point
|
||||
|
||||
**Common failures and workarounds:**
|
||||
|
||||
| Failure | Likely Cause | Manual Workaround |
|
||||
|---------|-------------|-------------------|
|
||||
| Extension not detected | Extension not installed or disabled | Install from Chrome Web Store |
|
||||
| Login screen appears | Session expired | Log in manually, then retry |
|
||||
| Source fails to process | URL is paywalled or blocked | Download content and add as pasted text instead |
|
||||
| Mindmap not available | Source volume too low | Add more sources (NotebookLM requires minimum content) |
|
||||
| Audio overview grayed out | Sources not yet indexed | Wait 1–2 minutes for indexing, then retry |
|
||||
|
||||
## Limitations
|
||||
|
||||
- **Chrome extension required** — This skill does not work in the Claude web interface without the extension. It cannot function in API-only or terminal-only Claude setups.
|
||||
- **NotebookLM UI changes** — If Google updates the NotebookLM interface, specific steps (button names, navigation paths) may need to be updated in this skill.
|
||||
- **Audio overview render time** — Audio overviews are queued server-side by NotebookLM and typically take 5–15 minutes. Claude can trigger the request but cannot wait for completion.
|
||||
- **File uploads** — Uploading local files (PDFs, docs) requires the file to be accessible from the browser. File paths must be absolute.
|
||||
- **Session state** — Claude cannot save or restore NotebookLM session state between conversations. Each session starts fresh.
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] User's full request was parsed into discrete steps before any browser action was taken
|
||||
- [ ] Ambiguous source references were clarified before proceeding
|
||||
- [ ] Each action was confirmed complete before the next one started
|
||||
- [ ] Direct notebook URL is included in the output
|
||||
- [ ] If audio overview was triggered, user was informed of the render delay
|
||||
- [ ] Any failed steps are explicitly reported with the specific failure reason
|
||||
- [ ] Manual workaround was offered for any step that failed
|
||||
- [ ] Output checklist accurately reflects what was completed vs. what failed
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "Open NotebookLM and create a notebook called 'Competitor Analysis Q2'"
|
||||
- "Add these 5 URLs as sources to my NotebookLM notebook"
|
||||
- "Generate a mindmap in NotebookLM from my current notebook"
|
||||
- "Create a NotebookLM notebook on AI agent frameworks, add these sources, and generate an audio overview"
|
||||
- "What notebooks do I have in NotebookLM?"
|
||||
- "Add this article to NotebookLM: [URL]"
|
||||
- "Generate a briefing doc from my NotebookLM sources on [topic]"
|
||||
@@ -0,0 +1,166 @@
|
||||
---
|
||||
name: notes-humanizer
|
||||
description: Strips AI writing patterns from text and rewrites it to sound genuinely human — not by softening it, but by removing statistical defaults and injecting the specific signals that human writers produce.
|
||||
---
|
||||
|
||||
# Notes Humanizer
|
||||
|
||||
"Humanize this" prompts don't work because they don't know what to remove. AI text has specific, identifiable defaults — em dashes used as parenthetical substitutes, rule-of-three lists where all items have identical rhythm, sentences that hover between 15 and 20 words. Fix those defaults, add the signals human writers actually produce, and the text stops reading as synthetic. This skill does that systematically, in two phases, and shows you exactly what changed and why.
|
||||
|
||||
> Credit: Originally created by Orel (TheIndiepreneur) — adapted and extended for this library.
|
||||
|
||||
---
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Format | Notes |
|
||||
|---|---|---|
|
||||
| Text to humanize | Paste directly into the chat | Any length. Works on paragraphs, full articles, social posts, emails. |
|
||||
|
||||
No other inputs required. Claude will not ask clarifying questions before starting — it works with what's given.
|
||||
|
||||
---
|
||||
|
||||
## Output Structure
|
||||
|
||||
### Section 1: What Was Found
|
||||
|
||||
A plain-language audit of the AI patterns detected in the original text, before any rewriting:
|
||||
|
||||
```
|
||||
PATTERNS DETECTED
|
||||
─────────────────
|
||||
Em dashes used as parenthetical substitutes: 3
|
||||
Filler openers ("Let's dive in", "It's worth noting", etc.): 2
|
||||
Rule-of-three lists with identical rhythm: 1
|
||||
Sentence length variance: low (avg 17 words, range 14–21)
|
||||
Hedging qualifiers: 4
|
||||
Passive constructions where active is cleaner: 2
|
||||
```
|
||||
|
||||
### Section 2: Side-by-Side Comparison
|
||||
|
||||
| Original | Rewritten |
|
||||
|---|---|
|
||||
| [original paragraph] | [rewritten paragraph] |
|
||||
|
||||
(One row per paragraph or logical block. Short texts get the full comparison in one table. Long texts get the table collapsed to changed sections only, with unchanged sections noted.)
|
||||
|
||||
### Section 3: Change Log
|
||||
|
||||
Every specific change made, with the reason:
|
||||
|
||||
```
|
||||
CHANGES MADE
|
||||
────────────────────────────────────────────────
|
||||
1. Removed em dash in "success — and it shows"
|
||||
→ Rewritten as "success (and it shows)"
|
||||
Why: em dash here is a parenthetical substitute, not a genuine pause
|
||||
|
||||
2. Deleted "It's worth noting that"
|
||||
Why: pure filler — the sentence is stronger without it
|
||||
|
||||
3. Broke rule-of-three list "X, Y, and Z"
|
||||
→ "X and Y. Z is different — [expanded thought]"
|
||||
Why: all three items had identical rhythm; broke the pattern
|
||||
|
||||
4. Added short sentence: "That's the problem."
|
||||
Why: needed a sub-8-word sentence to vary rhythm
|
||||
|
||||
5. Added sentence starting with "But"
|
||||
Why: human writers do this; AI avoids it as a statistical default
|
||||
|
||||
6. Added specific example: [detail added]
|
||||
Why: the original made an abstract claim with no grounding detail
|
||||
|
||||
7. Added aside: "(I've watched this fail three times in a row)"
|
||||
Why: breaks fourth wall slightly; signals genuine perspective
|
||||
```
|
||||
|
||||
### Section 4: Clean Output
|
||||
|
||||
The full rewritten text, ready to copy and paste — no annotations, no formatting artifacts.
|
||||
|
||||
```
|
||||
[Full rewritten text here]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Instructions for Claude
|
||||
|
||||
### Phase 1: Audit
|
||||
|
||||
Read the full text before making any changes. Identify and count every instance of these patterns:
|
||||
|
||||
**Patterns to remove or rewrite:**
|
||||
|
||||
| Pattern | Action |
|
||||
|---|---|
|
||||
| Em dash used as parenthetical substitute (`word — word` where a comma or parenthesis would work) | Replace with parentheses or rewrite the clause |
|
||||
| "Let's dive in" | Delete or replace with a direct first sentence |
|
||||
| "In conclusion" | Delete or rewrite as a genuine closing thought |
|
||||
| "It's worth noting that" | Delete — the sentence stands without it |
|
||||
| "At its core" | Delete or rewrite |
|
||||
| "Game-changer" | Replace with what the thing actually changes |
|
||||
| "Delve" | Replace with look, dig, explore — or rewrite the sentence |
|
||||
| "Navigate" used metaphorically for non-navigation tasks | Replace with a direct verb |
|
||||
| Rule-of-three lists where all three items have identical grammatical structure and similar word count | Break the third item out as its own sentence or expand it |
|
||||
| Sentences where every sentence in a paragraph falls in the 14–22 word range | Deliberately add one very short sentence and one longer one |
|
||||
| "Needless to say" | Delete |
|
||||
| "It's important to note that" | Delete |
|
||||
| Passive constructions where the active form is more direct | Flip to active |
|
||||
|
||||
Do not remove every em dash — only the ones used as parenthetical substitutes. Do not remove all hedging — only empty hedging that adds no information.
|
||||
|
||||
### Phase 2: Inject
|
||||
|
||||
After stripping patterns, add the following signals. Each one should emerge from the actual content — don't add generic filler:
|
||||
|
||||
1. **One genuine opinion or take.** The author appears to actually believe something specific. State it without hedging. ("This approach works, and I think most people underestimate how rarely the alternative does.")
|
||||
|
||||
2. **One specific detail, example, or number.** Ground the most abstract claim in the text with something concrete. If the text says "this happens frequently," add a real or illustrative number. If it says "many companies do this," name the type of company.
|
||||
|
||||
3. **One aside or parenthetical thought that breaks the fourth wall slightly.** This is the signal most synthetic text lacks — the writer momentarily steps out of the formal argument to say something human. ("(I've seen this specific mistake made by people who absolutely should have known better.)")
|
||||
|
||||
4. **At least one sentence under 8 words.** Make it land on a point, not a transition.
|
||||
|
||||
5. **One sentence that starts with "And" or "But."** Place it where the rhythm earns it, not randomly.
|
||||
|
||||
### Phase 3: Report
|
||||
|
||||
Present the output in the four-section structure defined above. The change log must list every individual change — not categories of change, but specific instances. If you changed three em dashes, list all three separately.
|
||||
|
||||
### Handling edge cases
|
||||
|
||||
- **If the text is already mostly clean:** Report what you found (or didn't find), make the few remaining changes, and note explicitly that the original was close. Don't invent problems.
|
||||
- **If the text is very short (under 100 words):** Skip the comparison table. Show original, then rewritten, then change log.
|
||||
- **If the text is over 1,500 words:** Process the full text but collapse the comparison table to changed sections only.
|
||||
|
||||
---
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] Audit was completed before rewriting (patterns counted, not just detected)
|
||||
- [ ] Every removed pattern is listed in the change log with a specific reason
|
||||
- [ ] Em dashes were assessed individually — only parenthetical-substitute uses were removed
|
||||
- [ ] Rule-of-three lists: the rhythm was actually checked, not just the fact that there were three items
|
||||
- [ ] At least one sentence under 8 words was added (or was already present)
|
||||
- [ ] At least one sentence starts with "And" or "But" in the final text
|
||||
- [ ] The specific detail or example added connects to an actual claim in the text, not floated in generically
|
||||
- [ ] The aside breaks the fourth wall slightly without being forced or cutesy
|
||||
- [ ] The change log lists specific instances, not categories
|
||||
- [ ] The clean output section has no annotations or formatting artifacts — ready to paste
|
||||
- [ ] If the original was already clean, that was stated explicitly rather than changes invented
|
||||
|
||||
---
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "Humanize this text: [paste]"
|
||||
- "Use the notes-humanizer skill on this draft"
|
||||
- "This reads like ChatGPT wrote it — fix it: [paste]"
|
||||
- "Strip the AI out of this and make it sound like a real person wrote it"
|
||||
- "Run the humanizer on this LinkedIn post: [paste]"
|
||||
- "This has too many em dashes and rule-of-three lists — clean it up: [paste]"
|
||||
- "Make this email sound less robotic: [paste]"
|
||||
@@ -0,0 +1,176 @@
|
||||
---
|
||||
name: substack-notes-scraper
|
||||
description: Scrapes a Substack Notes page and exports engagement data (likes, comments, restacks) to a formatted .xlsx file with conditional formatting and summary stats.
|
||||
---
|
||||
|
||||
# Substack Notes Scraper
|
||||
|
||||
Substack has no public API for Notes analytics. You can't see likes, comments, and restacks in one place without scrolling through your feed manually. This skill scrapes the rendered Notes page, filters to only your original content, and exports everything to a spreadsheet you can actually analyze.
|
||||
|
||||
> Credit: Originally created by a Substack newsletter author — adapted and extended for this library.
|
||||
|
||||
---
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Format | Example |
|
||||
|---|---|---|
|
||||
| Notes URL | Full URL to the Notes tab | `https://substack.com/@handle/notes` |
|
||||
| Author handle or name | Exact handle or display name | `@handle` or `Jane Smith` |
|
||||
| Date range | Plain English or explicit range | `last 30 days` or `Jan 2026 – Mar 2026` |
|
||||
|
||||
Claude will ask for these if not provided upfront.
|
||||
|
||||
---
|
||||
|
||||
## Output Structure
|
||||
|
||||
### File
|
||||
|
||||
```
|
||||
substack-notes-[handle]-[YYYY-MM-DD].xlsx
|
||||
```
|
||||
|
||||
### Sheet: "Notes Data"
|
||||
|
||||
| Column | Description |
|
||||
|---|---|
|
||||
| Date | Publication date (YYYY-MM-DD) |
|
||||
| Text Preview | First 200 characters of the note |
|
||||
| Full Text | Complete note text |
|
||||
| Likes | Like count at time of scrape |
|
||||
| Comments | Comment count |
|
||||
| Restacks | Restack count |
|
||||
| Total Engagement | Likes + Comments + Restacks |
|
||||
| Link | Direct URL to the note |
|
||||
| Note Type | `original` or `restack` |
|
||||
|
||||
**Formatting applied:**
|
||||
- Row 1: frozen header row
|
||||
- Auto-filter enabled on all columns
|
||||
- Top 20% by Likes column: highlighted yellow (`#FFF2CC`)
|
||||
- Column widths: auto-fit to content, min 12, max 60
|
||||
|
||||
### Sheet: "Summary"
|
||||
|
||||
```
|
||||
Scrape Date: [YYYY-MM-DD HH:MM UTC]
|
||||
Author: [handle]
|
||||
Date Range: [start] – [end]
|
||||
Total Notes: [n]
|
||||
Original Notes: [n]
|
||||
Restacks Filtered: [n]
|
||||
|
||||
Avg Likes: [n.n]
|
||||
Avg Comments: [n.n]
|
||||
Avg Restacks: [n.n]
|
||||
Avg Total Eng: [n.n]
|
||||
|
||||
Best Note (Likes): [date] — [first 80 chars] — [n] likes
|
||||
Best Note (Eng): [date] — [first 80 chars] — [n] total engagement
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Instructions for Claude
|
||||
|
||||
### Step 1: Validate inputs
|
||||
|
||||
Confirm the three required inputs are present. If any are missing, ask before proceeding. Parse the date range into a concrete start date and end date (convert relative ranges like "last 30 days" to explicit dates using today's date).
|
||||
|
||||
### Step 2: Fetch the Notes page
|
||||
|
||||
Use `WebFetch` to load the Notes URL. Substack Notes pages are JavaScript-rendered — request the full rendered HTML. If WebFetch returns a skeleton page without note content, note this in your response and ask the user to paste the page HTML manually or confirm browser access is available.
|
||||
|
||||
### Step 3: Paginate through all notes in the date window
|
||||
|
||||
Substack Notes load incrementally. Repeat fetching or scrolling until either:
|
||||
- A note's date falls outside the target date range (stop loading more), or
|
||||
- No new content loads on the next request.
|
||||
|
||||
Rate-limit: wait 2 seconds between each paginated request. Do not hammer the endpoint.
|
||||
|
||||
### Step 4: Parse each note
|
||||
|
||||
For every note element found on the page, extract:
|
||||
- **Date**: the timestamp on the note (convert to YYYY-MM-DD)
|
||||
- **Author**: the display name or handle shown on the note
|
||||
- **Full text**: complete body text, stripping HTML tags
|
||||
- **Text preview**: first 200 characters of full text
|
||||
- **Likes count**: the number shown on the like/heart counter
|
||||
- **Comments count**: the number shown on the comment counter
|
||||
- **Restacks count**: the number shown on the restack counter
|
||||
- **Link**: the direct permalink to the note
|
||||
- **Note type**: `original` if the author matches the specified author; `restack` if it belongs to someone else
|
||||
|
||||
### Step 5: Filter
|
||||
|
||||
Keep ALL rows in the data (restacks included as rows with `Note Type = restack`). The Summary sheet stats should count only `original` notes. Mark restacks clearly so the user can filter them out themselves in Excel if preferred.
|
||||
|
||||
Apply date filter: exclude any note outside the specified date range.
|
||||
|
||||
### Step 6: Calculate Total Engagement
|
||||
|
||||
For each row: `Total Engagement = Likes + Comments + Restacks`
|
||||
|
||||
### Step 7: Identify top 20% by Likes
|
||||
|
||||
Sort original notes by Likes descending. Mark the top 20% (round up) for conditional formatting. These rows will be highlighted yellow in the output file.
|
||||
|
||||
### Step 8: Build the .xlsx file
|
||||
|
||||
Use Python with `openpyxl` to generate the file. Structure:
|
||||
|
||||
```python
|
||||
# Required libraries
|
||||
import openpyxl
|
||||
from openpyxl.styles import PatternFill, Font, Alignment
|
||||
from openpyxl.utils import get_column_letter
|
||||
from datetime import datetime
|
||||
|
||||
# Sheet 1: Notes Data
|
||||
# - Write header row, bold, freeze row 1
|
||||
# - Write all data rows
|
||||
# - Apply auto-filter: ws.auto_filter.ref = ws.dimensions
|
||||
# - Apply yellow fill to top-20% rows by likes
|
||||
# - Auto-size columns (iterate cells to find max length)
|
||||
|
||||
# Sheet 2: Summary
|
||||
# - Write summary stats as key-value pairs, no table format
|
||||
```
|
||||
|
||||
Name the file `substack-notes-[handle]-[YYYY-MM-DD].xlsx` using today's date.
|
||||
|
||||
### Step 9: Report back
|
||||
|
||||
After generating the file, report:
|
||||
- File path
|
||||
- Total notes found, original vs. restacks
|
||||
- Date range actually covered
|
||||
- Top 3 notes by total engagement (date + preview + stats)
|
||||
- Any notes or warnings (e.g., page didn't fully load, some dates were ambiguous)
|
||||
|
||||
---
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] All three required inputs were confirmed before starting
|
||||
- [ ] Rate limiting honored: 2-second delay between paginated requests
|
||||
- [ ] Author filter applied correctly — restacks are included as rows but flagged, not silently dropped
|
||||
- [ ] Date range filter applied — no notes outside the window appear in the data
|
||||
- [ ] Total Engagement column is Likes + Comments + Restacks (not hardcoded)
|
||||
- [ ] Top 20% highlight is based on the actual data distribution, not a fixed threshold
|
||||
- [ ] Header row is frozen and auto-filter is active
|
||||
- [ ] Summary sheet stats reference only `original` notes, not restacks
|
||||
- [ ] File is named with the author handle and today's date
|
||||
- [ ] If the page failed to load properly, the user was told — not silently given an empty file
|
||||
|
||||
---
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "Scrape my Substack Notes and export to Excel — my handle is @handle, last 60 days"
|
||||
- "Use the substack-notes-scraper skill on https://substack.com/@handle/notes for Q1 2026"
|
||||
- "Pull my notes engagement data into a spreadsheet"
|
||||
- "Export my Substack Notes stats with likes and restacks — author: Jane Smith, Jan–Mar 2026"
|
||||
- "Run the Substack scraper on my notes page and show me which posts performed best"
|
||||
@@ -0,0 +1,156 @@
|
||||
---
|
||||
name: sycophancy-challenger
|
||||
description: Flips Claude's default from "find reasons you're right" to "find reasons you're wrong." A genuine thinking partner, not a mirror with grammar. Use before high-stakes decisions, plans, assumptions, or pitches you haven't stress-tested.
|
||||
---
|
||||
|
||||
# Sycophancy Challenger
|
||||
|
||||
Claude defaults to validating. You bring a decision, it finds three reasons your instinct is solid, and you leave more confident but not more right. That's actively dangerous when the stakes are high — a hiring call, a pricing change, a strategy pivot, a public commitment. This skill flips the default: Claude argues against your idea first, holds its position under pushback, and only concedes when you give it new evidence. Not when you express displeasure.
|
||||
|
||||
> Credit: Originally created by Joel Salinas (Leadership in Change) — adapted and extended for this library.
|
||||
|
||||
---
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Format | Notes |
|
||||
|---|---|---|
|
||||
| Your idea, decision, plan, or assumption | Describe it in plain language | More context = sharper challenge. Include reasoning if you have it. |
|
||||
|
||||
No other setup required. Activating the skill is enough — describe your idea and Claude will challenge it immediately.
|
||||
|
||||
---
|
||||
|
||||
## Output Structure
|
||||
|
||||
Every response in this mode follows this exact format:
|
||||
|
||||
```
|
||||
## Strongest Case AGAINST This
|
||||
|
||||
[The single most damaging criticism of the idea. Not a list of concerns — the
|
||||
one argument that, if true, would kill this. Stated directly, without softening.]
|
||||
|
||||
|
||||
## The Weakest Element
|
||||
|
||||
[The specific part of the idea most likely to fail, be wrong, or break under
|
||||
real-world conditions. Named precisely. Not "execution risk" — the actual thing.]
|
||||
|
||||
|
||||
## What You'd Need to Prove to Make This Work
|
||||
|
||||
[The assumptions that must be true for this idea to succeed. Written as testable
|
||||
claims, not as encouragement. If an assumption can't be tested, that's noted.]
|
||||
|
||||
|
||||
## What I Can't Find Fault With
|
||||
|
||||
[Only appears when a genuine search finds nothing damaging. States clearly what
|
||||
holds up and why — doesn't invent weak praise to fill the section. If everything
|
||||
is actually fine, says so plainly and explains why the challenge came up short.]
|
||||
```
|
||||
|
||||
No additional sections. No summary. No "overall, this is a solid idea." The format ends when the four sections are complete.
|
||||
|
||||
---
|
||||
|
||||
## Instructions for Claude
|
||||
|
||||
### On activation
|
||||
|
||||
Do not open with agreement, validation, or any form of "I see where you're coming from." Begin the challenge immediately. The first word of your response should advance the criticism, not soften the user's expectations.
|
||||
|
||||
### Step 1: Assume the idea hasn't been stress-tested
|
||||
|
||||
Treat the idea as if the user believes in it strongly and has not actively looked for reasons it fails. Your job is to be the adversary they didn't have in the room.
|
||||
|
||||
### Step 2: Find the strongest case against it
|
||||
|
||||
Not a balanced view. Not pros and cons. The strongest case against. Ask:
|
||||
- What's the most likely way this fails?
|
||||
- What's the assumption that, if wrong, makes everything else irrelevant?
|
||||
- Who would argue against this, and what's the best version of their argument?
|
||||
- What does this idea get wrong about how people, markets, or systems actually behave?
|
||||
|
||||
State the strongest case directly. Do not list multiple criticisms in this section — lead with the one that does the most damage.
|
||||
|
||||
### Step 3: Identify the weakest element
|
||||
|
||||
This is different from the strongest case against. The weakest element is the most fragile specific component — the thing most likely to crack under execution, scrutiny, or changed conditions. Name it precisely. Examples of insufficient answers:
|
||||
- "The timeline might be tight" → insufficient
|
||||
- "The assumption that customers will pay $99/month before experiencing the product is the element most likely to break this, because you have no evidence of willingness-to-pay at that price point" → correct level of specificity
|
||||
|
||||
### Step 4: Surface the required assumptions
|
||||
|
||||
List what must be true for this to work. Write each assumption as a testable claim:
|
||||
|
||||
```
|
||||
For this to work, the following must be true:
|
||||
1. [Assumption stated as a claim that can be verified or falsified]
|
||||
2. [Assumption stated as a claim]
|
||||
3. [Assumption stated as a claim]
|
||||
```
|
||||
|
||||
If an assumption cannot be tested — it's based on hope, belief, or unprovable prediction — flag it explicitly: "This assumption cannot currently be tested. That's a risk."
|
||||
|
||||
### Step 5: Report what holds up (only if true)
|
||||
|
||||
Search genuinely for what the idea gets right or where the challenge fails. If you find it, state it clearly. If you can't find a real flaw, say exactly that: "I've looked for the failure points and I can't find them. Here's what actually holds up: [specific things]." Do not invent praise. Do not invent flaws either.
|
||||
|
||||
### Handling pushback
|
||||
|
||||
If the user pushes back:
|
||||
- **New evidence or new information:** update your position based on the evidence. State what changed and why.
|
||||
- **Emotional pushback, repetition, or displeasure:** do not move. Restate the criticism calmly. Example: "I understand you feel strongly about this — I'm not backing off the point about X because that hasn't changed. If there's something I'm missing, tell me what it is."
|
||||
- **A clarification that changes the picture:** acknowledge the clarification, adjust if warranted, and explain exactly what the clarification changed.
|
||||
|
||||
Do not soften a position because the user seems upset. Do not move back to validation mode mid-conversation.
|
||||
|
||||
### When the skill ends
|
||||
|
||||
The session is complete when the user has either:
|
||||
1. Strengthened their idea by addressing the core criticism with real evidence or a genuine plan adjustment, or
|
||||
2. Identified a real flaw they're going to fix.
|
||||
|
||||
Not when they've expressed satisfaction. Not when a certain number of exchanges have happened. The measure is whether something actually changed or was genuinely defended.
|
||||
|
||||
### Prohibitions
|
||||
|
||||
These prohibitions do more work than the rules above. Follow them absolutely:
|
||||
|
||||
- **Never open with agreement or validation.** Not "That's an interesting approach," not "I can see why you'd think that." Start with the challenge.
|
||||
- **Never say "great question," "great point," or "I see where you're coming from" as a lead.** These are validation openers, not neutral transitions.
|
||||
- **Never soften a criticism with "however, there are also positives."** If the positives are real, they go in the "What I Can't Find Fault With" section, not as a counterweight to every criticism.
|
||||
- **Never back down because the user expressed displeasure.** Only move if given new evidence.
|
||||
- **Never invent a flaw that isn't real.** If the idea is actually solid, say so. Inventing fake criticisms is as useless as fake validation.
|
||||
- **Never use the word "valid" to describe the user's perspective mid-challenge.** It's a validation signal disguised as a neutral word.
|
||||
|
||||
---
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] Response opened with the challenge — not with a softening phrase or acknowledgment
|
||||
- [ ] "Strongest Case Against" section contains one argument, not a list
|
||||
- [ ] "Weakest Element" is specific — names the actual component, not a category of risk
|
||||
- [ ] "What You'd Need to Prove" lists testable assumptions, not encouragement
|
||||
- [ ] Untestable assumptions are explicitly flagged as risks
|
||||
- [ ] "What I Can't Find Fault With" only appears if the search was genuine and something held up
|
||||
- [ ] No invented flaws — every criticism connects to something real in what the user described
|
||||
- [ ] Pushback was met with a position restatement, not a retreat (unless new evidence was provided)
|
||||
- [ ] The session ended because something changed or was genuinely defended — not because the user seemed satisfied
|
||||
- [ ] None of the prohibited phrases or patterns appear anywhere in the response
|
||||
|
||||
---
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "Use the sycophancy-challenger skill — here's my plan: [describe it]"
|
||||
- "Challenge this idea before I commit to it: [describe it]"
|
||||
- "I've already decided to do X — tell me why I'm wrong"
|
||||
- "Be the devil's advocate on this hire: [describe the candidate and the role]"
|
||||
- "I'm about to pitch this to investors — tear it apart first: [describe it]"
|
||||
- "Don't validate this, challenge it: [idea or assumption]"
|
||||
- "Stress-test this strategy: [describe it]"
|
||||
- "What's the strongest argument against doing this: [decision]"
|
||||
- "I think I'm right about X — what am I missing?"
|
||||
@@ -0,0 +1,625 @@
|
||||
---
|
||||
name: thumbnail-creator
|
||||
description: "Generate article or newsletter thumbnail candidates using the Gemini API from inside Claude Code. Claude reads article copy, proposes composition concepts, writes image generation prompts incorporating brand specs, calls Gemini to generate the images, evaluates the results via computer vision, and returns ranked candidates with rationale. Use when asked to create thumbnails, generate cover images, or produce visual candidates for an article or newsletter."
|
||||
---
|
||||
|
||||
# Thumbnail Creator Skill (via Gemini)
|
||||
|
||||
Generates article and newsletter thumbnail candidates by acting as an image-generation agent inside Claude Code. Instead of switching between tools and prompting Gemini's web UI one image at a time, this skill makes Claude do the full loop: read the copy, propose compositions, write tailored prompts, call the Gemini API, evaluate the outputs, and return ranked results with brief rationale.
|
||||
|
||||
The output is production-ready thumbnail candidates you can drop directly into your CMS, newsletter tool, or social scheduler.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Both of these must be in place before the skill can generate images:
|
||||
|
||||
### 1. Gemini API Key
|
||||
|
||||
Get a free key from [Google AI Studio](https://aistudio.google.com/app/apikey).
|
||||
|
||||
Set it as an environment variable:
|
||||
|
||||
```bash
|
||||
export GEMINI_API_KEY="your-key-here"
|
||||
```
|
||||
|
||||
To persist it across sessions, add to your shell profile (`~/.zshrc` or `~/.bashrc`):
|
||||
|
||||
```bash
|
||||
echo 'export GEMINI_API_KEY="your-key-here"' >> ~/.zshrc
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
Verify it is set:
|
||||
|
||||
```bash
|
||||
echo $GEMINI_API_KEY
|
||||
```
|
||||
|
||||
### 2. generate_image.py Script
|
||||
|
||||
This script must exist at `./generate_image.py` in the project root. The full template is provided in the Script Template section below. Claude will check for it and offer to create it if missing.
|
||||
|
||||
**Python dependencies:**
|
||||
|
||||
```bash
|
||||
pip install google-generativeai Pillow requests
|
||||
```
|
||||
|
||||
Or with uv:
|
||||
|
||||
```bash
|
||||
uv pip install google-generativeai Pillow requests
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Required Inputs
|
||||
|
||||
Claude will ask for these if not provided:
|
||||
|
||||
| Input | Required | Notes |
|
||||
|---|---|---|
|
||||
| Article copy or URL | Yes | Paste the full article text, or provide a URL to fetch. Used to extract themes, hooks, and key claims for composition. |
|
||||
| Brand colours | Recommended | Hex codes or descriptive names. E.g. `#1A1A2E` (navy), `#E94560` (coral). If not provided, Claude uses clean neutral defaults. |
|
||||
| Fonts / type style | Recommended | E.g. "bold sans-serif", "editorial serif", "Neue Haas Grotesk". Used in prompt to guide text treatment. |
|
||||
| Style reference description | Recommended | E.g. "flat illustration, minimal, like Stripe's marketing site" or "photorealistic, dark background, high contrast". A style image URL can also be provided. |
|
||||
| Output dimensions | No | Defaults to `1792x1024` (landscape, standard article thumbnail). Options: `1024x1024` (square), `1024x1792` (portrait/mobile). |
|
||||
| Number of candidates | No | Defaults to 4. Min 1, max 8 (API limits and cost). |
|
||||
| Article title (if different from H1) | No | Used as the primary text element in image prompts. |
|
||||
| Candidate selection | No | After proposing compositions, Claude asks which to generate. User can say "all" or pick by number. |
|
||||
|
||||
---
|
||||
|
||||
## Output Structure
|
||||
|
||||
### Phase 1 — Composition Proposals (text, before any API calls)
|
||||
|
||||
Claude presents 3-4 composition concepts for user approval. Format:
|
||||
|
||||
```
|
||||
Composition Concepts for: "[Article Title]"
|
||||
|
||||
1. BOLD CLAIM
|
||||
Layout: Full-bleed dark background, large white headline centred,
|
||||
single accent data point (e.g. "3x faster") in brand colour below
|
||||
Mood: High authority, newsletter-style
|
||||
Best for: LinkedIn, Substack headers
|
||||
Rationale: The article's central claim ("X outperforms Y by 3x") is specific
|
||||
enough to anchor the visual — readers stop on data.
|
||||
|
||||
2. CONCEPTUAL OBJECT
|
||||
Layout: Central object illustration (e.g. a broken clock for a time-waste article),
|
||||
title in upper third, minimal texture background
|
||||
Mood: Editorial, Medium-style
|
||||
Best for: Blog header, Medium cover, email preheader
|
||||
Rationale: Gives art directors visual metaphor flexibility; works across sizes.
|
||||
|
||||
3. CONTRAST SPLIT
|
||||
Layout: Left half brand colour, right half white or image,
|
||||
title on colour side, supporting subtext on white side
|
||||
Mood: Clean, professional, startup-brand feel
|
||||
Best for: Newsletter, LinkedIn carousel first slide
|
||||
Rationale: Split layout performs consistently in newsletter A/B tests;
|
||||
text is readable at small sizes.
|
||||
|
||||
4. TYPOGRAPHIC ONLY
|
||||
Layout: No illustration, oversized title treatment,
|
||||
author name in small caps at bottom, thin rule separator
|
||||
Mood: Premium, confident, editorial
|
||||
Best for: Substack, Ghost, high-density email lists
|
||||
Rationale: Works when the brand has strong type identity. Fastest to produce.
|
||||
|
||||
Which compositions do you want generated? (Reply with numbers, e.g. "1, 3" or "all")
|
||||
```
|
||||
|
||||
### Phase 2 — Generated Image Files
|
||||
|
||||
After generation, Claude saves files to `./thumbnails/[article-slug]/`:
|
||||
|
||||
```
|
||||
thumbnails/
|
||||
└── article-slug-from-title/
|
||||
├── candidate_01_bold_claim.png
|
||||
├── candidate_02_conceptual_object.png
|
||||
├── candidate_03_contrast_split.png
|
||||
├── candidate_04_typographic.png
|
||||
└── evaluation_report.md
|
||||
```
|
||||
|
||||
### Phase 3 — Evaluation Summary Table
|
||||
|
||||
Claude evaluates each returned image via computer vision and produces:
|
||||
|
||||
```
|
||||
Thumbnail Evaluation — "[Article Title]"
|
||||
Generated: 2026-05-27 | Model: Gemini Imagen | Dimensions: 1792x1024
|
||||
|
||||
| # | Candidate | Composition | Brand Fit /10 | Text Legibility /10 | Recommendation |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | candidate_01_bold_claim.png | Bold Claim | 9 | 8 | ★ Top pick — strong data anchor, brand colours correct, title readable at 200px width |
|
||||
| 2 | candidate_02_conceptual_object.png | Conceptual Object | 7 | 9 | Good fallback — legible, clean, but illustration style drifted slightly from brand |
|
||||
| 3 | candidate_03_contrast_split.png | Contrast Split | 8 | 7 | Works well at full size; test at thumbnail size before publishing — right side text tightens |
|
||||
| 4 | candidate_04_typographic.png | Typographic | 9 | 10 | Strongest for email — zero brand drift risk, completely text-based |
|
||||
|
||||
Recommended for web: candidate_01_bold_claim.png
|
||||
Recommended for email/mobile: candidate_04_typographic.png
|
||||
Recommended for social: candidate_03_contrast_split.png
|
||||
|
||||
Files saved to: ./thumbnails/article-slug-from-title/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## How Claude Should Execute This Skill
|
||||
|
||||
### Step 1 — Ingest and analyse the article
|
||||
|
||||
Accept article copy as pasted text or a URL.
|
||||
|
||||
If a URL is provided, fetch the page and extract:
|
||||
- The H1 title
|
||||
- The first 3-5 paragraphs (the hook, central claim, and key points)
|
||||
- Any notable statistics or named frameworks mentioned
|
||||
- The author name (for typographic compositions)
|
||||
|
||||
If text is pasted, read it directly. Focus on:
|
||||
- **The hook:** What is the opening claim or tension?
|
||||
- **The central thesis:** What is the one thing the article argues or teaches?
|
||||
- **Key specifics:** Any numbers, named frameworks, or concrete examples that could anchor a visual
|
||||
- **Tone:** Is this formal/authoritative, conversational/accessible, provocative/challenge-based?
|
||||
|
||||
Summarise these findings internally before proposing compositions — the proposals should feel tailored to this specific article, not generic.
|
||||
|
||||
### Step 2 — Collect brand specs
|
||||
|
||||
Ask the user for brand specs if not provided:
|
||||
|
||||
```
|
||||
To generate on-brand thumbnails, I need a few details:
|
||||
|
||||
1. Brand colours (hex codes or descriptions) — e.g. #1A1A2E, #E94560
|
||||
2. Font style preference — e.g. "bold sans-serif", "editorial serif", "geometric"
|
||||
3. Visual style — e.g. "flat minimal", "photorealistic", "illustrated", "typographic only"
|
||||
4. Any style references — describe a brand or publication whose aesthetic you want to match,
|
||||
or share an image URL
|
||||
|
||||
If you don't have brand specs yet, say "use clean defaults" and I'll use a professional
|
||||
dark-on-white editorial style.
|
||||
```
|
||||
|
||||
If the user says "use clean defaults", apply:
|
||||
- Background: `#FFFFFF` or `#0F0F0F` (dark mode default)
|
||||
- Accent: `#2563EB` (blue)
|
||||
- Font style: bold geometric sans-serif
|
||||
- Style: minimal flat, no textures, high contrast
|
||||
|
||||
### Step 3 — Propose composition concepts
|
||||
|
||||
Write 3-4 composition concepts tailored to the article's tone and content. Each concept must:
|
||||
- Have a name (short, memorable label)
|
||||
- Describe the layout precisely (where title goes, what visual element anchors it, background treatment)
|
||||
- Note the mood and the use case it's best suited for
|
||||
- Include a rationale sentence explaining why this composition fits this specific article
|
||||
|
||||
After presenting the concepts, ask which to generate. Wait for user confirmation before making any API calls.
|
||||
|
||||
### Step 4 — Write Gemini image generation prompts
|
||||
|
||||
For each selected composition, write a detailed image generation prompt. Image generation prompts follow a different grammar than text prompts — they are descriptive, not instructional.
|
||||
|
||||
**Prompt structure:**
|
||||
```
|
||||
[Subject/composition] + [Style] + [Colour palette] + [Mood/lighting] +
|
||||
[Text treatment if any] + [What to avoid]
|
||||
```
|
||||
|
||||
**Example prompt for Bold Claim composition:**
|
||||
```
|
||||
Article thumbnail image. Large bold white sans-serif headline text reading "3x Faster Than
|
||||
Traditional Methods" centred on a deep navy blue background (#1A1A2E). Small coral accent
|
||||
text (#E94560) below reading the subtitle. Minimal flat design, no gradients, no stock photo
|
||||
elements, no people. Clean professional editorial style, high contrast, newsletter header
|
||||
format, 16:9 landscape orientation. The composition is typographic — text is the hero,
|
||||
no illustration required. Avoid: clip art, drop shadows, low contrast, crowded layout.
|
||||
```
|
||||
|
||||
**Prompt rules:**
|
||||
- Include exact hex colours when brand colours are provided
|
||||
- Specify the exact headline text to appear in the image
|
||||
- Name the style explicitly ("flat design", "editorial", "photorealistic") — Gemini responds well to style category names
|
||||
- Add a negative prompt ("Avoid: ...") at the end to reduce drift from brand style
|
||||
- Keep prompts under 300 words — longer prompts do not reliably produce better outputs
|
||||
|
||||
### Step 5 — Check prerequisites and run the generation script
|
||||
|
||||
Before calling the API, verify:
|
||||
|
||||
```bash
|
||||
# Check API key is set
|
||||
echo $GEMINI_API_KEY
|
||||
|
||||
# Check script exists
|
||||
ls -la ./generate_image.py
|
||||
|
||||
# Check dependencies
|
||||
python3 -c "import google.generativeai, PIL, requests; print('Dependencies OK')"
|
||||
```
|
||||
|
||||
If the script is missing, offer to create it using the template in the Script Template section below.
|
||||
|
||||
Run the generation script for each prompt:
|
||||
|
||||
```bash
|
||||
python3 generate_image.py \
|
||||
--prompt "your full prompt here" \
|
||||
--output "./thumbnails/article-slug/candidate_01_bold_claim.png" \
|
||||
--width 1792 \
|
||||
--height 1024
|
||||
```
|
||||
|
||||
Or pass all prompts in a batch config file:
|
||||
|
||||
```bash
|
||||
python3 generate_image.py --config ./thumbnails/article-slug/prompts.json
|
||||
```
|
||||
|
||||
### Step 6 — Evaluate generated images
|
||||
|
||||
After each image is saved, examine it using computer vision. Evaluate on two dimensions:
|
||||
|
||||
**Brand Fit (score /10):**
|
||||
- Are the brand colours correct? (1-2 points each)
|
||||
- Does the style match the requested aesthetic? (2 points)
|
||||
- Is the layout consistent with the composition brief? (2 points)
|
||||
- Are there any AI artefacts, distorted text, or unintended elements? (-1 per issue)
|
||||
|
||||
**Text Legibility (score /10):**
|
||||
- Is the headline text readable at full resolution? (3 points)
|
||||
- Is the headline text readable when the image is scaled to 300px wide (thumbnail size)? (3 points)
|
||||
- Is there sufficient contrast between text and background? (2 points)
|
||||
- Is the text placement within safe zones (not cut off at edges)? (2 points)
|
||||
|
||||
Note: Gemini Imagen sometimes renders text with spelling errors or distorted letterforms. If this happens, note it in the evaluation and suggest the user add the text overlay manually in Canva or Figma.
|
||||
|
||||
### Step 7 — Produce the evaluation report
|
||||
|
||||
Write the evaluation summary table (format shown in Output Structure section) and save it as `evaluation_report.md` in the output folder.
|
||||
|
||||
Include:
|
||||
- One-line rationale for each score
|
||||
- A top pick recommendation per use case (web, email/mobile, social)
|
||||
- Any production notes (e.g. "text rendering is imperfect on candidate_02 — overlay text manually")
|
||||
- The full prompts used, so the user can iterate directly in AI Studio if needed
|
||||
|
||||
### Step 8 — Offer iteration
|
||||
|
||||
After delivering the candidates, offer one iteration pass:
|
||||
|
||||
```
|
||||
Want me to iterate on any of these?
|
||||
|
||||
Options:
|
||||
- Adjust colours or style on a specific candidate
|
||||
- Try a different composition concept
|
||||
- Change the headline text
|
||||
- Rerun with different Gemini parameters (different temperature/seed)
|
||||
- Generate additional variants of the top pick
|
||||
|
||||
Just tell me what to change.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Script Template
|
||||
|
||||
Claude should offer to write this file if `generate_image.py` is not present. This is the canonical template to use.
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
generate_image.py — Gemini Imagen wrapper for Thumbnail Creator skill.
|
||||
|
||||
Usage:
|
||||
python3 generate_image.py --prompt "..." --output "./out.png" [--width 1792] [--height 1024]
|
||||
python3 generate_image.py --config ./prompts.json
|
||||
|
||||
Config JSON format:
|
||||
[
|
||||
{
|
||||
"prompt": "...",
|
||||
"output": "./thumbnails/slug/candidate_01.png",
|
||||
"width": 1792,
|
||||
"height": 1024
|
||||
}
|
||||
]
|
||||
|
||||
Requirements:
|
||||
pip install google-generativeai Pillow
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import argparse
|
||||
import base64
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import google.generativeai as genai
|
||||
from google.generativeai import types as genai_types
|
||||
except ImportError:
|
||||
print("ERROR: google-generativeai not installed. Run: pip install google-generativeai")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
import io
|
||||
except ImportError:
|
||||
print("ERROR: Pillow not installed. Run: pip install Pillow")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def get_api_key() -> str:
|
||||
key = os.environ.get("GEMINI_API_KEY", "")
|
||||
if not key:
|
||||
print("ERROR: GEMINI_API_KEY environment variable is not set.")
|
||||
print("Get a key at: https://aistudio.google.com/app/apikey")
|
||||
print("Then run: export GEMINI_API_KEY='your-key-here'")
|
||||
sys.exit(1)
|
||||
return key
|
||||
|
||||
|
||||
def generate_image(
|
||||
prompt: str,
|
||||
output_path: str,
|
||||
width: int = 1792,
|
||||
height: int = 1024,
|
||||
) -> bool:
|
||||
"""
|
||||
Call Gemini Imagen to generate a single image and save it to output_path.
|
||||
Returns True on success, False on failure.
|
||||
"""
|
||||
api_key = get_api_key()
|
||||
genai.configure(api_key=api_key)
|
||||
|
||||
# Determine aspect ratio from dimensions
|
||||
ratio = width / height
|
||||
if abs(ratio - 16/9) < 0.1:
|
||||
aspect_ratio = "16:9"
|
||||
elif abs(ratio - 1.0) < 0.1:
|
||||
aspect_ratio = "1:1"
|
||||
elif abs(ratio - 9/16) < 0.1:
|
||||
aspect_ratio = "9:16"
|
||||
else:
|
||||
aspect_ratio = "16:9" # default fallback
|
||||
|
||||
try:
|
||||
imagen_model = genai.ImageGenerationModel("imagen-3.0-generate-002")
|
||||
|
||||
result = imagen_model.generate_images(
|
||||
prompt=prompt,
|
||||
number_of_images=1,
|
||||
aspect_ratio=aspect_ratio,
|
||||
safety_filter_level="block_only_high",
|
||||
person_generation="allow_adult",
|
||||
)
|
||||
|
||||
if not result.images:
|
||||
print(f" No images returned for: {output_path}")
|
||||
return False
|
||||
|
||||
image_data = result.images[0]
|
||||
|
||||
# Ensure output directory exists
|
||||
Path(output_path).parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Save the image
|
||||
if hasattr(image_data, '_image_bytes'):
|
||||
img_bytes = image_data._image_bytes
|
||||
elif hasattr(image_data, 'image'):
|
||||
img_bytes = image_data.image
|
||||
else:
|
||||
# Fallback: try to access raw data
|
||||
img_bytes = bytes(image_data)
|
||||
|
||||
img = Image.open(io.BytesIO(img_bytes))
|
||||
|
||||
# Resize to exact dimensions if needed
|
||||
if img.size != (width, height):
|
||||
img = img.resize((width, height), Image.LANCZOS)
|
||||
|
||||
img.save(output_path, format="PNG", optimize=True)
|
||||
print(f" Saved: {output_path} ({img.size[0]}x{img.size[1]})")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f" ERROR generating image: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def run_from_args():
|
||||
parser = argparse.ArgumentParser(description="Gemini Imagen wrapper for thumbnail generation")
|
||||
parser.add_argument("--prompt", type=str, help="Image generation prompt")
|
||||
parser.add_argument("--output", type=str, help="Output file path (.png)")
|
||||
parser.add_argument("--width", type=int, default=1792, help="Image width in pixels")
|
||||
parser.add_argument("--height", type=int, default=1024, help="Image height in pixels")
|
||||
parser.add_argument("--config", type=str, help="JSON config file with batch of prompts")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.config:
|
||||
# Batch mode
|
||||
with open(args.config, "r") as f:
|
||||
items = json.load(f)
|
||||
print(f"Batch mode: {len(items)} image(s) to generate")
|
||||
results = []
|
||||
for i, item in enumerate(items, start=1):
|
||||
print(f"\n[{i}/{len(items)}] Generating: {item['output']}")
|
||||
ok = generate_image(
|
||||
prompt=item["prompt"],
|
||||
output_path=item["output"],
|
||||
width=item.get("width", 1792),
|
||||
height=item.get("height", 1024),
|
||||
)
|
||||
results.append({"output": item["output"], "ok": ok})
|
||||
|
||||
print(f"\nBatch complete: {sum(r['ok'] for r in results)}/{len(results)} succeeded")
|
||||
for r in results:
|
||||
status = "OK " if r["ok"] else "ERR"
|
||||
print(f" {status} {r['output']}")
|
||||
|
||||
elif args.prompt and args.output:
|
||||
# Single image mode
|
||||
print(f"Generating: {args.output}")
|
||||
ok = generate_image(
|
||||
prompt=args.prompt,
|
||||
output_path=args.output,
|
||||
width=args.width,
|
||||
height=args.height,
|
||||
)
|
||||
if ok:
|
||||
print("Done.")
|
||||
else:
|
||||
print("Failed.")
|
||||
sys.exit(1)
|
||||
|
||||
else:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_from_args()
|
||||
```
|
||||
|
||||
**To create this file from inside Claude Code:**
|
||||
```bash
|
||||
# Claude will write this file if it doesn't exist:
|
||||
ls ./generate_image.py || echo "Script missing — Claude will create it"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Prompt Writing Reference
|
||||
|
||||
Claude should use this reference when writing image generation prompts. These patterns produce the most consistent results with Gemini Imagen.
|
||||
|
||||
### Composition patterns
|
||||
|
||||
| Composition type | Prompt anchor phrase |
|
||||
|---|---|
|
||||
| Text-led, dark background | "Bold white sans-serif headline text on deep [colour] background, minimal flat design" |
|
||||
| Text-led, light background | "High-contrast black headline text on clean white background, editorial layout" |
|
||||
| Object/illustration centred | "Centred [object] illustration, [style], [colour] background, title text in upper third" |
|
||||
| Split layout | "Vertical split: left half [colour], right half white. Headline on left side, supporting text on right" |
|
||||
| Photography style | "Photorealistic [scene description], [mood] lighting, [colour] colour grade, text overlay area at [position]" |
|
||||
|
||||
### Style modifiers that work well with Gemini
|
||||
|
||||
- `flat design, no gradients` — clean vector-style outputs
|
||||
- `editorial magazine style` — sophisticated, typographic
|
||||
- `minimal, lots of whitespace` — reduces visual noise
|
||||
- `high contrast, bold typography` — strong thumbnail legibility
|
||||
- `Bauhaus-inspired` — geometric, structured
|
||||
- `dark mode aesthetic` — dark backgrounds with light text
|
||||
- `startup marketing style` — clean, optimistic, sans-serif
|
||||
|
||||
### Negative prompts (always include)
|
||||
|
||||
Append to every prompt:
|
||||
|
||||
```
|
||||
Avoid: stock photography clichés, clipart, excessive gradients, drop shadows,
|
||||
cluttered layout, lens flares, watermarks, low contrast text, AI artefacts.
|
||||
```
|
||||
|
||||
### Text rendering note
|
||||
|
||||
Gemini Imagen sometimes renders short text phrases accurately and longer headlines poorly. If the article headline is longer than 6 words, consider splitting it in the prompt:
|
||||
|
||||
```
|
||||
Primary headline: "[First 4-5 words]"
|
||||
Secondary text: "[Remaining words]"
|
||||
```
|
||||
|
||||
Or instruct the user to add text overlay manually in Canva after generation if legibility is critical.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Cause | Fix |
|
||||
|---|---|---|
|
||||
| `GEMINI_API_KEY not set` | Environment variable missing | Run `export GEMINI_API_KEY="your-key"` and retry |
|
||||
| `ModuleNotFoundError: google.generativeai` | Dependency missing | Run `pip install google-generativeai` |
|
||||
| `No images returned` | Safety filter triggered | Revise prompt to remove any ambiguous language; check that the prompt doesn't describe faces, violence, or brand logos |
|
||||
| Generated image has garbled text | Imagen text rendering limitation | Use shorter headline in prompt, or plan to add text overlay in Canva/Figma post-generation |
|
||||
| Image is the wrong size | Aspect ratio mismatch | Confirm `--width` and `--height` args match one of the supported ratios (16:9, 1:1, 9:16) |
|
||||
| `generate_image.py not found` | Script not created yet | Ask Claude to create it using the template above |
|
||||
| API quota exceeded | Free tier limit | Wait or upgrade to Gemini API paid tier |
|
||||
| Style drift from brand | Prompt not specific enough | Add exact hex codes and specific style descriptors; add stronger negative prompt |
|
||||
|
||||
---
|
||||
|
||||
## Quality Checks
|
||||
|
||||
Before marking the task complete, verify each item:
|
||||
|
||||
- [ ] `GEMINI_API_KEY` environment variable confirmed set before any API calls
|
||||
- [ ] `generate_image.py` script exists in project root — created from template if missing
|
||||
- [ ] All Python dependencies installed and verified (`google-generativeai`, `Pillow`)
|
||||
- [ ] Composition proposals were presented and user confirmed which to generate before any API calls
|
||||
- [ ] Each composition proposal is specific to this article's content — not generic placeholders
|
||||
- [ ] Brand colours (hex codes) are included in the image generation prompts
|
||||
- [ ] Negative prompt appended to every image generation prompt
|
||||
- [ ] Headline text in prompts is 6 words or fewer per text element (longer headlines split or noted as overlay candidates)
|
||||
- [ ] Output folder created at `./thumbnails/[article-slug]/` with correct slug derived from article title
|
||||
- [ ] Files named with candidate number and composition name (`candidate_01_bold_claim.png`)
|
||||
- [ ] Each generated image evaluated via computer vision — not assumed to be correct
|
||||
- [ ] Brand Fit and Text Legibility scores are specific and justified, not round numbers
|
||||
- [ ] Any text rendering issues noted in evaluation with "add text overlay manually" recommendation
|
||||
- [ ] Evaluation report saved as `evaluation_report.md` in the output folder
|
||||
- [ ] At least one recommendation given per use case: web, email/mobile, social
|
||||
- [ ] Full prompts used are included in the evaluation report for user iteration reference
|
||||
- [ ] Iteration offer made after delivering results
|
||||
|
||||
---
|
||||
|
||||
## Example Trigger Phrases
|
||||
|
||||
- "Create thumbnails for this article"
|
||||
- "Generate cover image candidates for my newsletter"
|
||||
- "Make me 4 thumbnail options for this post"
|
||||
- "Can you generate some thumbnail ideas using Gemini?"
|
||||
- "I need a featured image for this article — use my brand colours"
|
||||
- "Create a thumbnail for this piece using Gemini" [followed by article text or URL]
|
||||
- "Generate article cover images for these brand specs: [colours, style]"
|
||||
- "Make thumbnail candidates and rank them"
|
||||
- "I need newsletter header images — here's the copy"
|
||||
- "Generate and evaluate thumbnail options for this draft"
|
||||
- "Use Gemini to create cover image options"
|
||||
- "Thumbnail this article" [followed by article text]
|
||||
- "Create 3 thumbnail compositions and pick the best one"
|
||||
|
||||
---
|
||||
|
||||
## Cost and Rate Limits
|
||||
|
||||
**Gemini AI Studio free tier (as of early 2026):**
|
||||
- Imagen 3: 10 images per day (free)
|
||||
- Rate limit: varies by region and account tier
|
||||
|
||||
**Paid tier:**
|
||||
- Imagen 3 pricing: approximately $0.03-0.05 per image (check current Google Cloud pricing)
|
||||
- For a typical session generating 4-8 candidates, total cost is under $0.40
|
||||
|
||||
**Recommendation:**
|
||||
- Use the free tier for exploration and iteration
|
||||
- Generate final production candidates on paid tier for higher daily limits
|
||||
- For newsletter teams generating thumbnails weekly, the paid tier is more practical
|
||||
|
||||
---
|
||||
|
||||
*Originally created by Karen Spinner (Wondering About AI) — adapted and extended for this library.*
|
||||
Reference in New Issue
Block a user