paper-summarize
The auto pipeline ingests metadata + abstract only — Summary / Key Findings / Methodology / Relevance stay as [TODO] skeletons in both Obsidian and Zotero. Cluster-level summarization (NotebookLM brief, crystals) does NOT fill per-paper notes. So after auto, the user has nothing scannable per paper without opening the PDF.
This skill fills that gap. One LLM call per paper, JSON-validated, written to both vault systems atomically (rollback the markdown change if Zotero write fails so the two stay in sync).
When to use
Trigger phrases:
- "Summarize the papers in cluster X."
- "Fill the TODO Key Findings for X."
- "I just ran
auto Xand the notes are empty — give me real summaries." - "Update Zotero notes for cluster X with what each paper actually says."
Not for:
- Generating a single CLUSTER-LEVEL summary — that's
research-hub notebooklm generate(NotebookLM brief). - Filling Q&A on the cluster — that's
research-hub crystal emit/apply. - Reading PDFs — abstract-only by design. PDF parsing is out of scope; the LLM is told to mark "[PDF needed]" if abstract is too thin.
- Verifying brief vs source — that's
notebooklm-brief-verifier.
Inputs
- Cluster slug (must already exist in the vault under
raw/<slug>/) - Optional LLM CLI override (
claude,codex,gemini,opencode,aichat,cursor, or configured custom adapter) - Optional
--applyflag (default off, dry-run)
The skill reads each paper's frontmatter (DOI, year, zotero-key) + the ## Abstract body block. Papers with empty abstract get a "PDF needed" marker rather than hallucinated findings.
Outputs
For each paper, three sections are rewritten:
-
Obsidian markdown at
raw/<cluster>/<paper-slug>.md:## Key Findingscallout block (3–5 bullets)## Methodologycallout block (one sentence)## Relevancecallout block (1–2 sentences linking to the cluster topic)- Anchor IDs (
^findings,^methodology,^relevance) preserved.
-
Zotero child note for the paper's parent item (looked up via
zotero-keyfrontmatter):- Existing note HTML overwritten with
<h1>Summary+ Abstract + Key Findings<ul>+ Methodology + Relevance. - If no child note exists, one is created.
- Existing note HTML overwritten with
Both writes must succeed for a paper to count as "applied". A Zotero write failure rolls back the markdown change so the two systems stay in sync.
Failure modes
- No LLM CLI on PATH: prompt is saved to
<vault>/.research_hub/artifacts/<cluster>/summarize-prompt.md. The user pipes it through their LLM manually and re-runs with--apply, or calls theapply_cluster_summariesMCP tool with the parsed payload. Exit code 0; ok=True. - LLM returns malformed JSON: report is
ok=Falsewitherror="LLM response had no parseable JSON object". No writes. - Paper slug in payload not in cluster: that entry is skipped with reason logged; other entries still applied.
- Empty key_findings / methodology / relevance: entry skipped.
- Zotero write fails for one paper: that paper's markdown change is rolled back; other papers still applied.
Verification
This skill's contract is exercised end-to-end by the test suite. The suites stub the LLM CLI but execute real Obsidian markdown writes against a fixture vault and real Zotero child-note writes against a mocked Zotero adapter. Rollback semantics (markdown rolls back if Zotero write fails) are explicitly tested.
# Run the full paper-summarize suite (23 tests)
python -m pytest -q \
tests/test_v069_summarize.py \
tests/test_v073_parallel_summarize.py \
tests/test_v080_resummarize.py
Coverage breakdown:
| Test file | Count | What it covers |
|---|---|---|
| tests/test_v069_summarize.py | 17 | Prompt builder shape, validator (rejects unknown slugs / empty fields / wrong types), Obsidian + Zotero apply path, rollback when Zotero fails, no-LLM-on-PATH fallback |
| tests/test_v073_parallel_summarize.py | 3 | Parallel summarize across multiple clusters, ordering, error isolation |
| tests/test_v080_resummarize.py | 3 | Re-summarize behaviour: idempotent on same input, overwrite on different LLM output, --no-zotero path |
For a manual smoke check against a live vault:
# Dry-run (emit prompt + show LLM output, no writes)
research-hub summarize --cluster <slug>
# Live run (writes to Obsidian + Zotero)
research-hub summarize --cluster <slug> --apply
# Override LLM
research-hub summarize --cluster <slug> --llm-cli codex --apply
# Obsidian-only (skip Zotero — useful when Zotero is offline)
research-hub summarize --cluster <slug> --apply --no-zotero
After applying, scan raw/<cluster>/*.md — every paper's ## Key Findings callout should have real bullets instead of [TODO].
Operating notes
- Findings-first: the prompt instructs the LLM to state the result, not "The paper shows that…".
- Anchored to the abstract: every Key Finding must trace to something the abstract claims. The LLM is told to mark uncertain claims with
[likely]. - Idempotent: re-running on a cluster with already-filled findings will overwrite them with whatever the LLM produces this run. Use
--no-zoteroor--no-obsidianif you want to preview one side first. - Same dual-write discipline as the abstract-sync helpers in
.scratch/: one transactional unit per paper.
微信扫一扫