# Derive Thesis

> Name the CENTRAL SUBJECT (spine) of a long-form source so selection can tell on-theme moments from clip-shaped tangents. Claude reads the topic chapter list (topics.json) + source duration and emits thesis.json = {subject, thesis_sentence, key_threads[]} — the one durable source-level "what is this video about" artifact the pipeline lacked. Runs AFTER segment-topics and BEFORE pick-segments; pick-segments feeds it as a theme prior + scores each pick's theme_fit against it, and the confidence-floor backfill is gated on it so a high-standalone but off-spine tangent can no longer be auto-injected. Deterministic fallback (subject from the longest topic) on any failure. Non-fatal, idempotent, DERIVE_THESIS=0 skips.

- Skill: `jperrello/derive-thesis` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add jperrello/derive-thesis`
- Raw SKILL.md: https://api.skillmd.com/api/skills/jperrello/derive-thesis/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: jperrello (https://skillmd.com/u/jperrello)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/jperrello/derive-thesis

---


# derive-thesis

A 2-hour talk wanders through one core throughline plus dozens of entertaining
tangents. Nothing in the pipeline named the throughline, so `pick-segments`
maximized standalone virality per span and shipped clip-shaped asides (a beetle
anecdote, a DoorDash story) that misrepresent the source. `derive-thesis`
computes that missing source-level subject once, as a durable JSON artifact both
`pick-segments` (theme prior + `theme_fit` score + backfill gate) and
`selection-report` read.

## Invoke

```
.claude/skills/derive-thesis/derive-thesis.sh <transcript.json> [topics.json] [out.json]
```

- `transcript`: full-source transcript (for duration; the digest is the topic list)
- `topics`: `segment-topics` output (auto-discovered next to the transcript)
- `out`: `thesis.json` (auto-discovered next to the transcript)

## Output

`thesis.json`:

```json
{
  "subject": "Donald Hoffman on consciousness and reality",
  "thesis_sentence": "Perception is a species-specific interface, not a window onto objective reality.",
  "key_threads": ["conscious agents", "fitness beats truth", "spacetime is not fundamental", "the hard problem"]
}
```

On any Claude/parse failure it writes a deterministic fallback (`subject` from
the longest topic's title, `key_threads` from the leading topic titles,
`"fallback": true`) so downstream always has a subject.

## How

`build_prompt.py` renders the whole chapter list and asks Claude to name the
SPINE (not summarize every chapter) — the guest + core theme, the throughline
sentence, and the on-spine sub-themes. `parse_reply.py` validates and clamps,
falling back to a topic-derived subject when the reply is empty/unparseable.
Idempotent via mtime (`topics.json` → `thesis.json`); `DERIVE_THESIS=0` skips.

