Turn Kindle Highlights Into Real Book Summaries: A Local AI Agent with Python and Ollama

Your highlights are sitting unread in a folder. Build a fully offline agent that reads them and produces a structured summary — core thesis, key takeaways, action items — straight into your Obsidian vault.

Share
Turn Kindle Highlights Into Real Book Summaries: A Local AI Agent with Python and Ollama

If you read a lot, you know the two failure modes: you read it and forget it, or you highlighted it and never came back.

Highlights pile up — exported from Kindle, typed into Obsidian while reading — and quietly become digital hoarding. Turning them into something useful means sitting down and re-reading every line to write a summary, which takes exactly the kind of focused time you rarely have.

This is where cognitive automation earns its keep. In this guide we build a private AI agent with Python and Ollama that reads your raw highlights, extracts the core thesis, the key takeaways and actionable insights, and writes a structured book summary into your Obsidian vault — fully offline, with no monthly API bill.

Why do this locally

Summarising books with AI is not new. Doing it locally is meaningfully different:

1. Your thinking stays yours. Reading notes are rarely neutral — they carry opinions, reactions, personal goals. Processing them on your own machine means none of that leaves it.

2. Output shaped to your vault. You control the prompt, so the agent writes in your Markdown structure, uses your tags, and emits real bi-directional links ([[Note Name]]) that fit the vault you already have.

3. No cap on volume. Five books or a hundred, run it as often as you like. No token counting, no per-request cost.

How it works


[ Obsidian highlight note ] → [ Python script ] → [ Local Ollama LLM ] → [ Structured summary ]
      raw highlights            read + prompt         synthesise            note in Obsidian

1. Input — read a raw highlights file from Reading/Highlights/

2. Analysis — send it to Ollama with a prompt that asks the model to think like an executive editor

3. Output — write a clean summary note into Reading/Summaries/

What you need

  • Python 3.8+ (standard library only — nothing to install)
  • Ollama running at http://localhost:11434
  • A modelgemma2 or llama3.1 works well (ollama pull gemma2)
  • An Obsidian vault

The agent

Create book_summary_agent.py:


import os
import json
import urllib.request
from datetime import datetime

OBSIDIAN_VAULT_DIR = os.path.expanduser("~/ObsidianVault")
HIGHLIGHTS_DIR = os.path.join(OBSIDIAN_VAULT_DIR, "Reading", "Highlights")
SUMMARIES_DIR = os.path.join(OBSIDIAN_VAULT_DIR, "Reading", "Summaries")

OLLAMA_MODEL = "gemma2"
OLLAMA_URL = "http://localhost:11434/api/generate"

PROMPT_TEMPLATE = """
You are an expert at knowledge synthesis and writing book summaries.
Read the raw highlights and reading notes below, then synthesise them into a
structured, genuinely useful book summary.

[RAW HIGHLIGHTS]:
{raw_highlights}

Follow this structure exactly:

1. **Core Thesis:** the central argument of the book in 2-3 sentences
2. **Key Takeaways:** 3-5 main points, each with a short plain-language explanation
3. **Actionable Insights:** 3 things the reader can start doing immediately
4. **Memorable Quote:** the 1-2 most striking lines from the highlights
5. **Suggested Tags:** 3-5 tags in #tag format

Write concisely, in Markdown.
"""


def query_ollama(prompt):
    payload = {"model": OLLAMA_MODEL, "prompt": prompt, "stream": False}
    data = json.dumps(payload).encode("utf-8")
    req = urllib.request.Request(
        OLLAMA_URL, data=data, headers={"Content-Type": "application/json"})
    try:
        with urllib.request.urlopen(req) as response:
            return json.loads(response.read().decode("utf-8")).get("response", "")
    except Exception as e:
        print(f"Could not reach Ollama: {e}")
        return None


def process_book_highlights(filename):
    input_path = os.path.join(HIGHLIGHTS_DIR, filename)
    if not os.path.exists(input_path):
        print(f"File not found: {input_path}")
        return

    with open(input_path, "r", encoding="utf-8") as f:
        raw_highlights = f.read()

    book_name = os.path.splitext(filename)[0]
    print(f"Synthesising summary for: {book_name}...")

    ai_response = query_ollama(PROMPT_TEMPLATE.format(raw_highlights=raw_highlights))
    if not ai_response:
        print("No summary produced.")
        return

    os.makedirs(SUMMARIES_DIR, exist_ok=True)
    today_str = datetime.now().strftime("%Y-%m-%d")
    output_path = os.path.join(SUMMARIES_DIR, f"Summary - {book_name}.md")

    file_content = f"""---
title: "Summary: {book_name}"
date: "{today_str}"
type: "book-summary"
source_note: "[[{book_name}]]"
---

# Book Summary: {book_name}

> Synthesised locally on {today_str}

{ai_response}

---
*Generated from the raw highlights in `[[{filename}]]`*
"""

    with open(output_path, "w", encoding="utf-8") as f:
        f.write(file_content)

    print(f"Saved: {output_path}")


if __name__ == "__main__":
    process_book_highlights("Atomic-Habits-Highlights.md")

Running it

Drop a highlights file into Reading/Highlights/ — an export from Kindle works as-is — and run:


python3 book_summary_agent.py

The summary lands in Reading/Summaries/, already linked back to the source note. Open Obsidian and it is there, tagged and ready to connect to the rest of your vault.

Making it better

Two changes are worth making once it works:

  • Batch the whole folder. Loop over every file in Reading/Highlights/ and skip any that already have a summary. Then a year of reading gets processed in one run.
  • Tune the prompt to your own thinking. The default asks for an executive-editor summary. If you read mostly technical books, ask for the argument structure and the evidence behind each claim instead. This is the part worth iterating on — the model is the same, the prompt is what makes the output yours.

The point is not the summary itself. It is that highlights stop being a graveyard and start becoming a connected part of what you actually know.

Read more

สร้าง AI Agent สำหรับการทำ Decision Log อัตโนมัติ: เปลี่ยนทุกการตัดสินใจสำคัญให้เป็นบทเรียนเพื่อการเติบโต

สร้าง AI Agent สำหรับการทำ Decision Log อัตโนมัติ: เปลี่ยนทุกการตัดสินใจสำคัญให้เป็นบทเรียนเพื่อการเติบโต

เรียนรู้วิธีใช้ AI Agent ช่วยบันทึกและวิเคราะห์การตัดสินใจสำคัญในชีวิตประจำวัน เพื่อเปลี่ยนทุกทางเลือกให้กลายเป็นฐานข้อมูลบทเรียนที่มีค่าสำหรับอนาคต

By Linn
คู่มือใช้งาน Obsidian Graph View: เปลี่ยนใยแมงมุมความรู้ให้เป็นเครื่องมือนำทางความคิดใน Second Brain

คู่มือใช้งาน Obsidian Graph View: เปลี่ยนใยแมงมุมความรู้ให้เป็นเครื่องมือนำทางความคิดใน Second Brain

Graph View ใน Obsidian ไม่ใช่แค่ภาพกราฟสวยๆ ไว้ดูเล่น มาเรียนรู้วิธีปรับแต่ง Local Graph, Color Groups และฟิลเตอร์ เพื่อเปลี่ยนเครือข่ายความรู้ให้กลายเป็นเครื่องมือนำทางความคิดจริง

By Linn
สร้าง Smart Clipboard Agent: ดักจับและคัดแยกข้อความที่คัดลอกระหว่างวัน บันทึกเข้า Obsidian อัตโนมัติด้วย Python + Ollama

สร้าง Smart Clipboard Agent: ดักจับและคัดแยกข้อความที่คัดลอกระหว่างวัน บันทึกเข้า Obsidian อัตโนมัติด้วย Python + Ollama

เปลี่ยนข้อความ โค้ด ลิงก์ และไอเดียที่คุณคัดลอกระหว่างวันให้กลายเป็นบันทึกความรู้ที่มีบริบทใน Second Brain โดยอัตโนมัติ ด้วยสคริปต์ Python คอยมอนิเตอร์คลิปบอร์ดคู่กับ Local LLM บน Ollama แบบออฟไลน์ 100%

By Linn
บอกลาคำสั่ง Docker CLI ที่ซับซ้อน: คู่มือติดตั้ง Dockge จัดการ Docker Compose บน Home Server อย่างมือโปร

บอกลาคำสั่ง Docker CLI ที่ซับซ้อน: คู่มือติดตั้ง Dockge จัดการ Docker Compose บน Home Server อย่างมือโปร

ยกระดับการจัดการคอนเทนเนอร์บน Home Server ให้ง่ายและเป็นระเบียบ ด้วย Dockge ตัวจัดการ Docker Compose สไตล์มินิมอลที่เน้นความโปร่งใส ควบคุมไฟล์ .yml ได้โดยตรง 100%

By Linn