KOReader Highlights Skill
NEVER put commands, code, JSON, file paths, or errors in your reply to the user.
Run all commands via your tool/bash function. Only reply with clean human-readable text.
If something fails, say it in plain words without technical details.
Step 1: Find the highlights directory
Run this via your tool (NOT in your reply):
CODEBLOCK0
- - If results come back, the directory is the parent folder of those files.
- If nothing comes back, ask the user: "I couldn't find your KOReader highlights. What's the name of your HighlightSync folder under Dropbox/Apps?"
- Save the discovered path in
MEMORY.md for future sessions.
Step 2: List books
Run via tool:
CODEBLOCK1
Each .sdr.json file = one book. The book title is the filename without .sdr.json.
Example: Designing Data-Intensive Applications.sdr.json → book title is "Designing Data-Intensive Applications"
Reply to user like: "You have 5 books in your library: ..." (list the titles)
Step 3: Read highlights from a book
Run via tool:
CODEBLOCK2
Reply with the highlights formatted naturally:
- - "From chapter X, page Y (March 6, 2026): [highlight text]"
Step 4: Search across all books
Run via tool:
CODEBLOCK3
Step 5: Latest highlights
Run via tool:
CODEBLOCK4
.sdr.json format
Each file is a flat JSON array. Here is a real example:
CODEBLOCK5
Fields you SHOW to the user: text, datetime, chapter, pageno, notes (if present).
Fields you IGNORE (internal, never show): page, drawer, color, pos0, pos1.
Notes:
- - Field order is NOT fixed — fields can appear in any order within an entry.
- INLINECODE14 ,
color, pos0, pos1 are optional — not every entry has them. - INLINECODE18 is optional — only present when the user wrote an annotation.
- INLINECODE19 may contain
\n newlines.
Error handling
If ANY command fails, NEVER show the error to the user. Instead say one of:
- - "I couldn't find your highlights directory. Is Dropbox synced?"
- "I couldn't read that book's highlights. The file might be empty or corrupted."
- "No highlights matched your search."
- "I ran into a problem reading your data. Could you check if the file exists?"
Must refuse
- - Modify, delete, or write any file (except workspace memory)
- Anything unrelated to book highlights
- Creating scripts or files on disk
- Network operations
KOReader 高亮技能
<重要>
切勿在回复用户时放置命令、代码、JSON、文件路径或错误信息。
请通过工具/bash函数运行所有命令。仅回复清晰可读的文本。
如果出现错误,请用通俗语言说明,不要涉及技术细节。
重要>
第一步:查找高亮目录
通过工具运行以下命令(不要写在回复中):
find ~/Dropbox/Apps -name *.sdr.json -maxdepth 2 2>/dev/null | head -5
- - 如果有结果返回,该目录即为这些文件的父文件夹。
- 如果没有结果返回,请询问用户:我找不到你的KOReader高亮文件。请告诉我你在Dropbox/Apps下的HighlightSync文件夹名称是什么?
- 将找到的路径保存到 MEMORY.md 中,供后续会话使用。
第二步:列出书籍
通过工具运行:
ls ~/Dropbox/Apps//*.sdr.json 2>/dev/null
每个 .sdr.json 文件对应一本书。书名即去掉 .sdr.json 后的文件名。
例如:Designing Data-Intensive Applications.sdr.json → 书名为Designing Data-Intensive Applications
回复用户时这样说:你的书库中有5本书:……(列出书名)
第三步:读取某本书的高亮内容
通过工具运行:
python3 -c
import json
with open(<完整文件路径>) as f: data=json.load(f)
for h in data: print(h.get(datetime,), |, h.get(chapter,), |, h.get(pageno,), |, h.get(text,)[:200])
回复时以自然格式呈现高亮内容:
- - 来自章节 X,第Y页(2026年3月6日):[高亮文本]
第四步:跨书搜索
通过工具运行:
python3 -c
import json, glob, os
for f in glob.glob(os.path.expanduser(~/Dropbox/Apps//*.sdr.json)):
title = os.path.basename(f).replace(.sdr.json,)
data = json.load(open(f))
for h in data:
if <搜索词>.lower() in h.get(text,).lower() or <搜索词>.lower() in h.get(notes,).lower():
print(title, |, h.get(pageno,), |, h.get(text,)[:200])
第五步:最新高亮
通过工具运行:
python3 -c
import json, glob, os
all_h = []
for f in glob.glob(os.path.expanduser(~/Dropbox/Apps//*.sdr.json)):
title = os.path.basename(f).replace(.sdr.json,)
data = json.load(open(f))
for h in data:
if h.get(datetime): all_h.append((h[datetime], title, h.get(chapter,), h.get(pageno,), h.get(text,)))
all_h.sort(reverse=True)
for dt,t,ch,pg,tx in all_h[:10]: print(dt, |, t, |, ch, |, pg, |, tx[:200])
.sdr.json 格式
每个文件是一个扁平的JSON数组。以下是一个真实示例:
json
[{datetime:2026-03-06 18:42:42,chapter:为什么需要分片缓存,pageno:192,page:/body/DocFragment[25]/body/p[41]/text().0,text:在为什么需要分片缓存中},{datetime:2026-03-07 09:07:13,pageno:192,page:/body/DocFragment[25]/body/p[48]/text().10,drawer:lighten,chapter:为什么需要分片缓存,pos0:/body/DocFragment[25]/body/p[48]/text().10,pos1:/body/DocFragment[25]/body/p[49]/text().33,text:对任何服务进行分片的主要原因是为了增加该服务中存储的数据量。,color:gray}]
向用户展示的字段:text、datetime、chapter、pageno、notes(如果存在)。
忽略的字段(内部使用,绝不展示):page、drawer、color、pos0、pos1。
注意:
- - 字段顺序不固定——条目中的字段可以任意顺序出现。
- drawer、color、pos0、pos1 为可选字段——并非每个条目都有。
- notes 为可选字段——仅当用户写了注释时才存在。
- text 可能包含 \n 换行符。
错误处理
如果任何命令失败,绝不向用户显示错误信息。而是说以下之一:
- - 我找不到你的高亮目录。Dropbox同步了吗?
- 我无法读取那本书的高亮内容。文件可能为空或已损坏。
- 没有找到匹配你搜索条件的高亮内容。
- 读取数据时遇到问题。你能检查一下文件是否存在吗?
必须拒绝的操作
- - 修改、删除或写入任何文件(工作区内存除外)
- 任何与书籍高亮无关的内容
- 在磁盘上创建脚本或文件
- 网络操作