Build from zero · Agent-facing playbook
從零搭起 Kobo 閱讀與 Book Companion 系統
這不是假設有一個現成 Skill 可以裝。這份文件是給 agent 的施工圖:建立工具、資料夾、指令檔、Kobo authentication、EPUB parser、閱讀進度,以及可跟使用者一起設計的 interpret 工作流。
目標是讓同事把這頁交給自己的本機 agent,agent 就能一步步把同等能力建立起來,並在過程中訪談他的閱讀偏好與公司知識需求。
本機 instructions、觸發詞、閱讀流程與安全邊界。
`kobodl` 負責登入、書庫匯出與 EPUB 取得。
固定本機資料夾保存 EPUB,方便搜尋、續讀、備份。
用 script 輸出 `info`、`toc`、`chapter` JSON。
深度解讀、章節 Q&A、下一章、跳章、目錄。
可選擇接入 Vault、strategy docs、project docs。
local JSON、agent memory 或使用者選的筆記系統。
1. 先把前提說清楚
Agent 不應該把這套東西當成一個已經存在的包。它要照這份 manual 建出一個本機系統,然後和使用者一起決定哪些行為要變成自己的閱讀習慣。
- 確認使用者的 agent workspace、書籍資料夾、Kobo 帳號狀態。
- 安裝 `kobodl`、`jq`、Python parser environment。
- 建立本機資料夾、instruction file、EPUB reader script。
- 完成 Kobo browser auth,匯出書庫 JSON。
- 下載或指定一本 EPUB,跑 `info`、`toc`、`chapter`。
- 訪談 Book Companion 的語氣、深度、context、進度儲存。
- 跑第一章解讀,確認這就是使用者想要的閱讀體驗。
2. 參考資料夾結構
Marcus 的本機版本長這樣。其他人不需要照抄路徑,但要保留同樣的分層:instructions、scripts、references、books、state。
~/clawd/
.claude/skills/ebook-manage/
SKILL.md
scripts/
epub_reader.py
references/
kobodl-reference.md
reading-companion-guide.md
reading-companion-style.md
state/
reading-companion/
progress.json
~/Books/kobo/
Author - Book Title abc12345.epub
放 agent 讀得到的工作流說明、觸發詞、路徑與輸出規格。
放 `epub_reader.py` 和 Python venv,讓章節抽取可重複驗證。
放 progress JSON 或連接到使用者選的 memory/note system。
3. 工具與環境安裝
預設 macOS + Homebrew;如果使用者是其他 OS,agent 應該換 package manager,但保留同樣的 Python venv 與資料夾設計。
建立資料夾
mkdir -p "$HOME/clawd/.claude/skills/ebook-manage/scripts"
mkdir -p "$HOME/clawd/.claude/skills/ebook-manage/references"
mkdir -p "$HOME/clawd/state/reading-companion"
mkdir -p "$HOME/Books/kobo"
安裝 CLI 與 Python deps
brew install pipx jq
pipx ensurepath
pipx install kobodl
python3 -m venv "$HOME/clawd/.venvs/ebook-manage"
"$HOME/clawd/.venvs/ebook-manage/bin/python" -m pip install --upgrade pip
"$HOME/clawd/.venvs/ebook-manage/bin/python" -m pip install ebooklib beautifulsoup4 lxml
驗證工具
kobodl --help >/dev/null
"$HOME/clawd/.venvs/ebook-manage/bin/python" - <<'PY'
import ebooklib
import bs4
import lxml
print("epub parser deps ok")
PY
4. Kobo Authentication
Kobo 由 `kobodl` 做 browser auth。這套系統不要求使用者把 Kobo 密碼、cookie 或 raw API key 貼進聊天。
kobodl user add
kobodl user list
kobodl book list
kobodl book list --read
kobodl book list --export-library /tmp/kobo-library.json
你的 Kobo 帳號能不能用 email login?如果只有 Google/Facebook SSO,要先在 Kobo 補一個 email login 方法。
`kobodl user list` 有帳號、`book list --read` 看得到書、JSON export 可以被 `jq` 讀取。
5. 書庫操作
Agent 要把 Kobo JSON 轉成好選的書單,而不是把原始輸出丟給使用者。
kobodl book list --read --export-library /tmp/kobo-library.json
jq 'length' /tmp/kobo-library.json
# After the user picks a book:
kobodl book get "$REVISION_ID" --output-dir "$HOME/Books/kobo"
ls -lh "$HOME/Books/kobo"/*.epub
| JSON field | Purpose | Agent behavior |
|---|---|---|
| `BookEntitlement.Created` | 購買或加入日期 | 預設由新到舊排序。 |
| `BookEntitlement.RevisionId` | 下載識別碼 | 使用者選書後拿它下載。 |
| `ReadingState.StatusInfo.Status` | 閱讀狀態 | 支援 unread / reading / finished filter。 |
| `CurrentBookmark.ProgressPercent` | Kobo 端進度 | 顯示但不要當成本機進度唯一來源。 |
| `BookMetadata.Title` | 書名 | 支援模糊搜尋。 |
| `ContributorRoles[].Name` | 作者 | 顯示在選書表格。 |
6. EPUB Reader Script
Interpret 的內容來源必須是 parser 抽出的章節文字。不要只靠 TOC、metadata 或記憶猜。
#!/usr/bin/env python3
"""Deterministic EPUB metadata, TOC, and chapter extraction."""
import json
import re
import sys
from pathlib import Path
import ebooklib
from bs4 import BeautifulSoup
from ebooklib import epub
def strip_html(content: bytes) -> str:
soup = BeautifulSoup(content, "html.parser")
for tag in soup(["script", "style"]):
tag.decompose()
text = soup.get_text(separator="\n")
return re.sub(r"\n{3,}", "\n\n", text).strip()
def resolve_href(href: str) -> str:
return href.split("#")[0]
def flatten_toc(toc, depth=0):
entries = []
for item in toc:
if isinstance(item, tuple):
section, children = item
entries.append({
"title": section.title,
"href": resolve_href(section.href) if hasattr(section, "href") else None,
"depth": depth,
"is_section": True,
})
entries.extend(flatten_toc(children, depth + 1))
else:
entries.append({
"title": item.title,
"href": resolve_href(item.href),
"depth": depth,
"is_section": False,
})
for index, entry in enumerate(entries):
entry["index"] = index
return entries
def chapter_content(book, href: str) -> str:
for item in book.get_items_of_type(ebooklib.ITEM_DOCUMENT):
if item.get_name() == href or item.get_name().endswith(href):
return strip_html(item.get_body_content())
return ""
def load_book(epub_path: str):
path = Path(epub_path).expanduser()
if not path.exists():
print(json.dumps({"error": f"File not found: {path}"}, ensure_ascii=False))
sys.exit(1)
return epub.read_epub(str(path)), path
def cmd_info(epub_path: str):
book, path = load_book(epub_path)
title = book.get_metadata("DC", "title")
author = book.get_metadata("DC", "creator")
language = book.get_metadata("DC", "language")
print(json.dumps({
"title": title[0][0] if title else "Unknown",
"author": author[0][0] if author else "Unknown",
"language": language[0][0] if language else "Unknown",
"chapters": len(flatten_toc(book.toc)),
"file": str(path.resolve()),
}, ensure_ascii=False, indent=2))
def cmd_toc(epub_path: str):
book, _ = load_book(epub_path)
toc_flat = flatten_toc(book.toc)
for entry in toc_flat:
href = entry.get("href")
entry["chars"] = len(chapter_content(book, href)) if href else 0
print(json.dumps(toc_flat, ensure_ascii=False, indent=2))
def cmd_chapter(epub_path: str, index: int):
book, _ = load_book(epub_path)
toc_flat = flatten_toc(book.toc)
if index < 0 or index >= len(toc_flat):
print(json.dumps({"error": f"Index {index} out of range"}, ensure_ascii=False))
sys.exit(1)
entry = toc_flat[index]
content = chapter_content(book, entry.get("href") or "")
print(json.dumps({
"index": index,
"title": entry["title"],
"chars": len(content),
"total_chapters": len(toc_flat),
"content": content,
}, ensure_ascii=False, indent=2))
def main():
if len(sys.argv) < 3:
print("Usage: epub_reader.py info|toc|chapter <epub_path> [index]")
sys.exit(1)
command = sys.argv[1]
epub_path = sys.argv[2]
if command == "info":
cmd_info(epub_path)
elif command == "toc":
cmd_toc(epub_path)
elif command == "chapter":
if len(sys.argv) < 4:
print(json.dumps({"error": "Missing chapter index"}, ensure_ascii=False))
sys.exit(1)
cmd_chapter(epub_path, int(sys.argv[3]))
else:
print(json.dumps({"error": f"Unknown command: {command}"}, ensure_ascii=False))
sys.exit(1)
if __name__ == "__main__":
main()
chmod +x "$HOME/clawd/.claude/skills/ebook-manage/scripts/epub_reader.py"
EPUB="$HOME/Books/kobo/example.epub"
PY="$HOME/clawd/.venvs/ebook-manage/bin/python"
READER="$HOME/clawd/.claude/skills/ebook-manage/scripts/epub_reader.py"
"$PY" "$READER" info "$EPUB"
"$PY" "$READER" toc "$EPUB"
"$PY" "$READER" chapter "$EPUB" 0
7. Book Companion
這層不是摘要機器,而是閱讀夥伴。它要保留作者的推理、案例、概念轉折,並在必要時接回使用者自己的工作脈絡。
---
name: ebook-manage
description: Kobo eBook library management and Book Companion reading workflow.
---
# eBook Manage
Use this workflow when the user asks to browse Kobo books, read an EPUB,
continue a book, interpret a chapter, or move to the next chapter.
## Default Paths
- Workspace: ~/clawd
- Books: ~/Books/kobo
- Reader script: ~/clawd/.claude/skills/ebook-manage/scripts/epub_reader.py
- Parser Python: ~/clawd/.venvs/ebook-manage/bin/python
- Progress: ~/clawd/state/reading-companion/progress.json
## Reading Flow
1. Select a book from Kobo library or direct EPUB path.
2. Download the selected Kobo EPUB if needed.
3. Run epub_reader.py info.
4. Run epub_reader.py toc.
5. Ask where to start unless resuming.
6. Run epub_reader.py chapter.
7. Interpret the extracted chapter.
8. Save progress.
9. Offer next chapter, previous chapter, jump, TOC, or Q&A.
## Interpretation Contract
- Explain what problem the chapter is solving.
- Reconstruct the author's reasoning chain.
- Preserve important examples, definitions, and metaphors.
- Add analysis, but separate it from the author's claim.
- Use user/company context only when relevant.
- End with navigation options.
讀書、讀這本、幫我讀、繼續讀、下一章、上一章、目錄、跳到第 X 章、book companion。
章節問題、核心論點、作者敘事順序、框架圖、對使用者工作的意義、takeaways、下一步導航。
8. 使用者知識脈絡
如果使用者希望解讀能理解自己的公司、策略或 Obsidian Vault,agent 要先建立一個 context layer,而不是把私有資料硬塞進每段文字。
Obsidian Vault、project docs、strategy docs、company knowledge base、meeting notes、manual context file。
每章只抓 3-7 個真正相關的 context,說清楚為什麼相關,不要喧賓奪主。
沒有搜尋系統時,用 `rg` 先做資料夾內關鍵字搜尋,再請使用者確認範圍。
VAULT_PATH="$HOME/Obsidian"
rg -n "strategy|roadmap|growth|principle|decision|product" "$VAULT_PATH"
9. 客製化訪談
核心建起來後,agent 要帶使用者做一輪 product discovery。這套系統最值錢的地方,是它可以變成使用者自己的閱讀 operating system。
| Area | Default | Question |
|---|---|---|
| Book source | Kobo + local EPUB | 只讀 Kobo,還是也接本機 EPUB? |
| Interpret depth | Deep/adaptive | 你想要摘要、導讀、深度專欄,還是依章節密度調整? |
| Context lens | Relevant only | 要不要連到你的公司策略、專案、Vault?哪些資料夾安全? |
| Progress | Local JSON | 進度要存在 JSON、agent memory、還是 Obsidian note? |
| Knowledge capture | Ask first | 讀到好的 principle,要不要累積到公司共同知識? |
| Output | Chat | 要只回聊天,還是產生 Markdown reading note? |
Agent brainstorming prompts
- 當你說一篇解讀「有幫助」,它應該幫你讀完後做什麼?
- 這個 companion 比較像老師、策略夥伴、研究助理,還是讀書筆記助手?
- 哪些公司脈絡應該影響解讀?哪些東西不該被帶進來?
- 每章是否要抽出 reusable principles?要存到哪裡?
- 如果書中的觀點和你現在的策略衝突,agent 要不要直接指出?
- 你自然會輸入哪些閱讀指令?
10. End-To-End 驗證
不要只確認檔案存在。必須用一本真實 EPUB 跑完 auth、書庫、parser、interpret、progress。
kobodl user list
kobodl book list --read --export-library /tmp/kobo-library.json
jq 'length' /tmp/kobo-library.json
EPUB="$HOME/Books/kobo/example.epub"
PY="$HOME/clawd/.venvs/ebook-manage/bin/python"
READER="$HOME/clawd/.claude/skills/ebook-manage/scripts/epub_reader.py"
"$PY" "$READER" info "$EPUB"
"$PY" "$READER" toc "$EPUB"
"$PY" "$READER" chapter "$EPUB" 0
Kobo auth 可用、JSON export 成功、至少一本 EPUB 可被 parser 抽出章節、progress 可保存並續讀。
安裝了什麼、auth 狀態、書籍資料夾、測試 EPUB、parser 輸出摘要、使用者選的客製化設定。