Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions changelog/20260713194847-wrapup-angle-quality.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# indie-hacker-wrapup: session traceability + angle-quality fixes

- Ledger rows now carry `profile:` (`.claude` vs `.claude-pro`), `theme:`, `src:`, and an evidence anchor, so a logged angle links back to the session and profile that produced it. Pinned the ledger to the literal `~/.claude/` path so both agent profiles share one file instead of forking.
- Added a fourth scoring check (originality) with a banned-cliché list, an archetype-diversity rule, theme-level dedup, and a stronger inside-baseball guard — to stop the skill emitting specific-but-formulaic, already-said angles.
- Rewrote `references/angle-examples.md` to teach diverse post archetypes and the novelty gate instead of a single reversal template.
- Why: angles read generic and had no traceability back to their session.
41 changes: 31 additions & 10 deletions skills/indie-hacker-wrapup/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,20 @@ Calibration lives next to this file. When you need a worked sense of what separa

## Step 0 — Load the ledger of past angles

Before scanning, read the ledger of angles already pitched in earlier sessions:
Before scanning, read the ledger of angles already pitched in earlier sessions. The ledger always lives at this literal path:

`~/.claude/indie-hacker-wrapup/suggested-angles.md`

Use `~/.claude/` verbatim — never a `$CLAUDE_CONFIG_DIR`-relative path. Both agent profiles (`.claude` and `.claude-pro`) share this one ledger on purpose, so dedup sees every past angle regardless of which profile you are running under. Writing it under the active config dir would fork the ledger in two and break dedup.

If it exists, hold its lines as the "already pitched" set. You weigh new candidates against it in Step 3. If it does not exist yet, treat the set as empty. Step 3 creates the file the first time you present a shortlist.

**Row format.** Current rows carry structured tags:

`- [YYYY-MM-DD] [profile:<.claude|.claude-pro>] [theme:<slug>] [src:<repo-or-project-slug>] <angle> — evidence: <the concrete session fact it traces to>`

Older legacy rows are the bare `- [YYYY-MM-DD] <angle>` shape with no tags. When you dedup against a legacy row, infer its theme best-effort from the line text so history still participates.

## Step 1 — Read the session on two lenses

Review what actually happened this session, and mine it on two lenses, not one. Most weak wrap-ups happen because only the first lens ever gets used, so the post is always about engineering process and never about what was built.
Expand Down Expand Up @@ -50,6 +58,8 @@ Lens B is repo-aware. Decide first whether this session is your own indie projec

**Under-mining guard.** If every candidate you are holding is a Lens-A craft angle and not one is Lens B, you under-looked. Go back to what was built and who it is for before moving on. A session that shipped a real product almost always has a Lens-B angle.

**Inside-baseball guard.** Most sessions here are meta-work on the agent setup itself — model routing, code-review agents, statusline tokens, CLAUDE.md gates, doc-sync. Those fascinate the person who did them and bore everyone else. For every candidate, ask: would this land with someone who does NOT build AI agents or use Claude Code? If no, it is niche-of-niche → demote it hard, and prefer the Lens-B product/domain angle over the Lens-A agent-config angle. An angle about the thing you built beats an angle about how you configured the tool that built it.

Two hard filters, applied to every candidate on both lenses before it becomes real:

- **Privacy.** Drop anything employer-confidential, client- or teammate-identifying, NDA-bound, or personally sensitive. Never put private work content into a public draft.
Expand All @@ -63,25 +73,35 @@ The strongest posts often connect two facts the session kept separate. Example s

## Step 3 — Score, dedup, decide, record

**Score against an absolute bar first.** For each candidate, from either lens, check three things:
**Score against an absolute bar first.** For each candidate, from either lens, check four things. All four must pass:

- Does it teach the reader something they can use?
- Is there a concrete number, a reversal, or a genuine surprise in it?
- Would a stranger who does not know you stop scrolling and care?
- **Usable.** Does it teach the reader something they can act on?
- **Surprise.** Is there a concrete number, a reversal, or a genuine surprise in it?
- **Stranger cares.** Would a stranger who does not know you stop scrolling and care?
- **Original.** Is the core claim something the reader has NOT already seen a hundred times? An angle that reduces to a generic build-in-public maxim fails here unless this session adds a genuinely new twist. Reject on sight, no matter how specific the session detail dressed around it: "built ≠ shipped", "just ship it / ship volume", "use cheaper models for grunt work", "trust but verify", "green tests can still be wrong", "done is better than perfect", "talk to your users", "distribution is the only moat", "AI wrote 90% of my code". If your angle is one of these with a new coat of paint, it is not original. Kill it or find the twist that is actually new.

An angle must clear all three to be a candidate. If nothing clears the bar → say so plainly, in a line or two, and stop. Do not force a weak post. A skipped post beats a generic one. Rank whatever clears the bar by how hard it clears it. That ranking, not ledger novelty, sets the shortlist order.
An angle must clear all four to be a candidate. If nothing clears the bar → say so plainly, in a line or two, and stop. Do not force a weak post. A skipped post beats a generic one, and most sessions should yield zero or one, not five — if you are holding five, your bar slipped. Rank whatever clears the bar by how hard it clears it. That ranking, not ledger novelty, sets the shortlist order.

**Then dedup against the ledger from Step 0.** Dedup is theme-and-evidence aware, not binary:
**Diversify the shortlist by archetype.** A shortlist of five contrarian-reversal takes is one post written five ways — that monotony is what makes wrap-ups read generic. When you have more than one candidate, spread them across distinct post archetypes rather than stacking the same shape. Archetypes to draw from: specific-story-with-tension (what broke, what you did, how it turned), strong-opinion / hot-take, useful-resource or how-to (a concrete thing the reader can go use), honest-failure (what went wrong and the cost), counterintuitive-data (a real number that upends an assumption). If every survivor is the same archetype, keep only the single strongest and say so, rather than padding with clones.

**Then dedup against the ledger from Step 0.** Dedup is theme-and-evidence aware, not binary. Work at the theme level first: group candidates and ledger rows by their `theme:` tag (infer it for legacy rows), because the recurring failure here is the same theme resurfacing session after session under new specifics.

- **Theme already logged 2+ times** → that theme is exhausted. Drop the candidate unless it opens a materially new sub-angle within the theme, and if you keep it, say plainly it is the Nth time this theme has come up.
- **Clear repeat with no new strength** → drop it silently. It is already covered.
- **Stronger instance** of a logged angle, where this session is materially better evidence than the logged version (shipped vs merely planned, a real metric vs a hypothetical, a live bug caught vs a theoretical one) → keep it, re-pitched and flagged inline with the prior date, for example "stronger evidence than the one you logged on 2026-06-29, re-pitch?". Let the user judge. A great angle backed by fresh proof beats staying silent because a thin version was logged once.
- **Borderline** (similar but not obviously the same idea) → keep it, flag it inline with the date you logged it before. Suppressing a genuinely new angle is the costlier mistake, so when unsure, surface and flag rather than drop.

If dedup empties the shortlist (every angle is a clear repeat with no new strength) → tell the user the angles here overlap with ones already covered, name them, and stop. Record nothing new.
If dedup empties the shortlist (every angle is a clear repeat or an exhausted theme) → tell the user the angles here overlap with ones already covered, name them, and stop. Record nothing new.

For each surviving angle, give the angle in one line plus one line on why it would land with X readers, and carry the concrete session detail into the pitch — the specific scene, not the generalized maxim. Let the user pick. If they defer, take the top-ranked one.

**Record now, before the user picks.** The moment you present the shortlist, append every angle in it (fresh, stronger-instance, and flagged-borderline alike) to the ledger, one row each in the structured format:

`- [YYYY-MM-DD] [profile:<basename of $CLAUDE_CONFIG_DIR, default .claude>] [theme:<slug>] [src:<repo-or-project-slug>] <the angle in one line> — evidence: <the concrete session fact it traces to>`

For each surviving angle, give the angle in one line plus one line on why it would land with X readers. Let the user pick. If they defer, take the top-ranked one.
Get today's date from `date +%F` and the profile from `basename "${CLAUDE_CONFIG_DIR:-$HOME/.claude}"`. Pick a short stable `theme:` slug (reuse an existing one when the angle fits it) and an `src:` slug for the repo or project the session worked on. Create `~/.claude/indie-hacker-wrapup/` and the file (with a `# Suggested X angles (do not re-suggest)` header) if they do not exist. This happens in the same turn you show the shortlist, so an angle is remembered even when the user never picks one. Angles you dropped as clear repeats are already in the ledger, so do not write them again.

**Record now, before the user picks.** The moment you present the shortlist, append every angle in it (fresh, stronger-instance, and flagged-borderline alike) to the ledger, one per line as `- [YYYY-MM-DD] <the angle in one line>`, using today's date from `date +%F`. Create `~/.claude/indie-hacker-wrapup/` and the file (with a `# Suggested X angles (do not re-suggest)` header) if they do not exist. This happens in the same turn you show the shortlist, so an angle is remembered even when the user never picks one. Angles you dropped as clear repeats are already in the ledger, so do not write them again.
**Mark the winner.** Once the user picks an angle to draft (Step 4), prefix its ledger row with `★ ` so future runs can tell what was actually posted apart from what was merely pitched.

**Override.** If the user tells you to ignore the ledger or re-pitch a past angle, do it and surface the logged angle.

Expand All @@ -94,6 +114,7 @@ X-native craft:
- Open with a hook. The first line has to stop the scroll on its own.
- One idea per post. Cut everything that does not serve it.
- Concrete over generic. Real numbers, the real tool, what actually broke.
- Lead with the specific scene, not the lesson. Open on the concrete thing that happened and let the takeaway land after — a post that opens on the generalized maxim ("built ≠ shipped") reads as advice everyone has heard. The specific moment is what earns the general point.
- No hashtag spam, no engagement bait, no thread theatrics.
- Keep it inside a single tweet by default. If the idea genuinely needs room, offer a thread version instead of cramming.

Expand Down
64 changes: 47 additions & 17 deletions skills/indie-hacker-wrapup/references/angle-examples.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,74 @@
# Angle examples — weak vs strong
# Angle examples — weak vs strong, across archetypes

Calibration for Steps 1 to 3. Each pair shows the weak version most wrap-ups settle for next to the stronger angle hiding in the same session. The pattern to internalize: the weak one is almost always a craft-process observation that is true but forgettable. The strong one teaches the reader something about the problem, or reverses an assumption they hold.
Calibration for Steps 1 to 3. Two things this file trains: how to lift a weak angle into a strong one, and how to keep the strong ones from all sounding the same.

## Pair 1 — the case this skill was fixed on
The failure mode this skill keeps hitting: every angle comes out as the same shape — a contrarian reversal, *"X you thought was Y is actually Z."* Each one is fine alone. Five in a row read as a generic AI-thought-leader feed. So the examples below deliberately land in different archetypes. Match the archetype to what actually happened in the session, do not force everything into the reversal mold.

## The weak-to-strong lift

The weak version is almost always a craft-process observation that is true but forgettable. The strong one teaches the reader something about the problem, reverses an assumption they hold, or tells a story with real tension.

### Pair 1 — reversal archetype (the case this skill was fixed on)

Session: flipped a spend dashboard from counting only the "extra" overage to counting real gross AI usage. Employer work.

- **Weak (craft, what actually got surfaced):** "Test theater. My tests passed after a sort-key flip, but they would have passed without it because the fixture set both values equal." True, mildly interesting to engineers, forgettable to everyone else.
- **Strong (product domain, universal lesson):** "You are probably reading your AI spend wrong. If you only track the overage beyond your plan's included budget, you are blind to everything the plan absorbs. The real number is gross usage." Same session. A reader can check it on their own bill tonight.
- **Weak (craft):** "Test theater. My tests passed after a sort-key flip, but they would have passed without it because the fixture set both values equal." True, mildly interesting to engineers, forgettable to everyone else.
- **Strong (reversal, Lens B):** "You are probably reading your AI spend wrong. If you only track the overage beyond your plan's included budget, you are blind to everything the plan absorbs. The real number is gross usage." Same session. A reader can check it on their own bill tonight.

Why the strong one wins: it is Lens B, it survives the employer-privacy filter because the lesson is universal (no org, no real numbers), and a stranger cares because they share the blind spot.
Why it wins: it survives the employer-privacy filter because the lesson is universal (no org, no real numbers), and a stranger cares because they share the blind spot.

## Pair 2 — synthesis beats extraction
### Pair 2 — synthesis archetype

Session: built a tool that measures AI-tool spend, using a workflow that itself burned several model tiers and two AI code reviewers.

- **Weak (atomic):** "I used cheaper models for grunt tasks and kept the expensive one for hard reasoning." A generic, already-logged routing tip.
- **Weak (atomic):** "I used cheaper models for grunt tasks and kept the expensive one for hard reasoning." A generic, already-logged routing tip — and a banned cliché (see the novelty gate).
- **Strong (synthesized irony):** "I built a dashboard to measure AI spend with a workflow that was itself a heavy AI spend. The tool and the way I made it are the same story." Only visible if you synthesize in Step 2. Atomic extraction walks past it.

## Pair 3 — personal project, be specific
### Pair 3 — specific-story archetype (personal project, be specific)

Session: shipped a new onboarding flow on your own indie app and conversion moved.

- **Weak:** "Refactored the signup form into smaller components." Craft, no one cares.
- **Strong (specific, because it is yours):** "Cut my signup from 3 screens to 1 and activation went from X percent to Y percent in a week." On your own project you name the app, the number, the result. That specificity is the post.
- **Strong (story with a number):** "Cut my signup from 3 screens to 1 and activation went from X percent to Y percent in a week." On your own project you name the app, the number, the result. That specificity is the post.

The repo rule: specificity like Pair 3 is allowed only when the project is yours. For employer or client work, reduce to the universal lesson, as in Pair 1.

## The resonance bar, worked
### Pair 4 — honest-failure archetype

Session: a concurrent agent session ran a git pull mid-task and moved uncommitted work onto main.

- **Weak (reversal, forced):** "Turns out running parallel agents on one repo is risky." A truism dressed as insight.
- **Strong (failure, told straight):** "Two Claude sessions, one repo. One of them checked out main and pulled while the other still had uncommitted work in the tree. My own pre-commit review caught it a second before it landed on main. Here is the exact guard I added." Names what broke, the near-miss, and the fix the reader can copy. Failure with a receipt beats a lesson with none.

### Pair 5 — useful-resource archetype

Session: found a no-auth way to pull a Google Doc as clean markdown.

- **Weak:** "Learned you can export Google Docs to markdown." Vague, sounds like a docs page.
- **Strong (resource, give the exact thing):** "Any Google Doc share link → clean markdown, no API, no auth: hit the `/export?format=md` endpoint on the doc id. Drops straight into a pipeline." The reader can paste it and use it in ten seconds. A resource post earns its slot by being immediately actionable, not by being a hot take.

## The novelty gate, worked

The originality check is the fourth bar, and it is where most generic angles die. Run it after the first three pass.

Candidate: "Built it, but never deployed it — you can max every 'done' axis and still have zero users because you never shipped."

- Usable? Sort of. Surprise? Mild. Stranger cares? Maybe.
- Original? **No.** This is "built ≠ shipped," the single most repeated maxim in the indie-hacker canon. Reject it — unless the session adds a twist that is genuinely new. Here the twist might be: "I had 126 passing tests, 8 ADRs, a vision doc, and an SEO plan — every proxy for done except the one that makes signal. The polish was the procrastination." That reframes the cliché into something specific and self-implicating. Without a twist that sharp, it does not ship.

The point: session-specific detail does not buy originality. A stale idea with fresh numbers is still stale. Find the twist or drop it.

Run the three checks before an angle earns a slot.
## The resonance bar, worked (all four checks)

Candidate: "A migration default silently answers two questions at once, what new rows get and what existing rows get."

- Teaches something usable? Yes. Readers write migrations and have hit this.
- Concrete reversal or surprise? Yes. "One default, two questions" is a genuine reframe.
- Would a stranger care? Yes. It is a trap they can now avoid.
- Usable? Yes. Readers write migrations and have hit this.
- Surprise? Yes. "One default, two questions" is a genuine reframe.
- Stranger cares? Yes. It is a trap they can now avoid.
- Original? Yes. Not a canonical maxim, and the framing is not one you see repeated.

Clears all three, so it is a candidate. Rank it against the others by how hard it clears, then dedup against the ledger.
Clears all four, so it is a candidate. Rank it against the others by how hard it clears, then dedup against the ledger by theme.

Candidate: "Renamed a service file and updated its imports."

- Teaches something? No. Fails the first check and never reaches the shortlist.
- Usable? No. Fails the first check and never reaches the shortlist.
Loading