Install
openclaw skills install librarianConversational interface for semantic book search (companion skill for Librarian project)
openclaw skills install librarianVersion: 2.0.0 (Protocol-driven)
Status: 🚧 Development
Architecture: Sandwich (🎤 Skill → 👷 Wrapper → ⚙️ Python)
Search your book library using natural language. Ask questions like "What does Graeber say about debt?" and get precise citations with page numbers.
flowchart TB
TRIGGER["🎤 Trigger + context"]:::ready
TRIGGER --> METADATA["👷 Load metadata 1️⃣"]:::ready
METADATA --> CHECK{"👷 Metadata exists?"}:::ready
CHECK -->|No| ERROR["🎤 🤚 No metadata found:<br>Run librarian index 5️⃣"]:::ready
CHECK -->|Yes| INFER{"🎤 Infer scope? 2️⃣"}:::ready
INFER -->|confidence lower than 75%| CLARIFY["🎤 🤚 Say it again? 5️⃣"]:::ready
INFER -->|confidence higher than 75%| BUILD["👷 Build command 3️⃣"]:::ready
BUILD --> CHECK_SYSTEM{"⚙️ System working?"}:::ready
CHECK_SYSTEM -->|No| BROKEN["🎤 🤚 System is broken 5️⃣"]:::ready
CHECK_SYSTEM -->|Yes| EXEC["⚙️ Run python script with flags"]:::ready
EXEC --> JSON["⚙️ Return JSON"]:::ready
JSON --> CHECK_RESULTS{"👷 Results found?"}:::ready
CHECK_RESULTS -->|No| EMPTY["🎤 🤚 No results found 5️⃣"]:::ready
CHECK_RESULTS -->|Yes| FORMAT["🎤 Format output 4️⃣"]:::ready
FORMAT --> RESPONSE["🎤 Librarian response"]:::ready
classDef ready fill:#c8e6c9,stroke:#81c784,color:#2e7d32
Status: ✅ All nodes ready (v0.15.0 complete)
Protocol Nodes:
.library-index.json + .topic-index.json filespython3 research.py "QUERY" --topic TOPIC_IDSandwich Architecture:
Flow: 🎤 Skill → 👷 Sh → ⚙️ Py → 👷 Sh → 🎤 Skill
Why this pattern:
Symbols:
You are a messenger, not the system.
When wrapper returns error codes:
ERROR_NO_METADATA → "Não tem metadata. Roda librarian index."ERROR_INVALID_SCOPE → "Não entendi. Reformula? (topic ou book?)"ERROR_EXECUTION_FAILED → "Sistema quebrado."ERROR_NO_RESULTS → "Não achei nada sobre [query]."STOP THERE. Do NOT:
Hard stop = SUCCESS. You detected system state and reported honestly.
You didn't create the problem. You're just telling the truth:
Reporting hard stops IS your job done. ✅
How metadata is organized:
.library-index.json (BIG PICTURE)
├─ 73 topics total
├─ Each topic: {id, path}
└─ NO book list (prevents JSON explosion)
Each topic folder:
└─ .topic-index.json (NARROW)
└─ books: [{id, title, filename, author, tags, filetype}, ...]
Navigation:
.library-index.json only).library-index.json → infer topics → scan .topic-index.json files)🔴 CRITICAL: Extension Handling
User NEVER mentions file extensions.
Examples:
Why: Extension = metadata detail (epub vs pdf), irrelevant to user.
Your job:
title (NO extension)filename to wrapper (WITH extension: "I Ching.epub")Metadata fields:
.library-index.json → topics list (big picture).topic-index.json → books list per topic (narrow view)title (user-facing, no ext) + filename (internal, with ext)Full taxonomy: See backstage/epic-notes/metadata-taxonomy.md
Activate when user query matches ANY of these patterns:
Book/Author references:
Topic keywords (with confidence >75%):
Explicit commands:
If confidence <75% → CLARIFY (ask user)
Determine WHAT to search (topic or book) from user intent.
AI = router. Intelligence is in the index (embeddings). You just match query → scope.
Read metadata (.library-index.json):
{
"books": ["Debt - The First 5000 Years.epub", "I Ching of the Cosmic Way.epub"],
"topics": ["chaos-magick", "finance", "anarchy"]
}
Fuzzy match query against metadata:
| Match book? | Match topic? | → Action |
|---|---|---|
| ✅ | ✅ | TOPIC (tiebreaker: future mixed searches) |
| ✅ | ❌ | BOOK |
| ❌ | ✅ | TOPIC |
| ❌ | ❌ | CLARIFY (hard stop) |
Match rules:
TOPIC wins (tiebreaker):
BOOK only:
TOPIC only:
CLARIFY (no match):
Topic scope: --topic TOPIC_ID
Book scope: --book FILENAME
Execute wrapper script with inferred scope:
./librarian.sh "QUERY" SCOPE_TYPE SCOPE_VALUE [TOP_K]
Arguments:
QUERY: User's search query (exact string)SCOPE_TYPE: "topic" or "book"SCOPE_VALUE: topic_id or book filenameTOP_K: Number of results (default: 5)Example calls:
# Topic search
./librarian.sh "What is debt?" "topic" "finance" 5
# Book search
./librarian.sh "hexagram 23" "book" "I Ching of the Cosmic Way.epub" 5
The wrapper returns structured status via exit codes:
librarian index)Exit 1 (NO_METADATA):
🤚 Your library isn't indexed yet.
Run this first:
librarian index
(This scans your books/ folder and creates search indexes)
Exit 2 (BROKEN):
🤚 Something's broken in the research engine.
I tried to search but got a system error. Nicholas needs to debug this.
(Check: Python dependencies, research.py syntax, FAISS indexes)
Exit 3 (NO_RESULTS):
🤚 No results found for "[QUERY]"
Try:
- Broader terms (e.g., "debt" instead of "sovereign debt crisis")
- Different scope (search topic instead of single book?)
- Check spelling
When wrapper returns success (exit 0), format the JSON results for the user.
{
"results": [
{
"text": "Full chunk text...",
"book_title": "Debt: The First 5000 Years",
"similarity": 0.89,
"filename": "Debt - The First 5000 Years.epub",
"location": "p.45, ¶3",
"page": 45,
"paragraph": 3,
"filetype": "pdf"
}
],
"metadata": {
"query": "What is debt?",
"topic": "finance",
"returned": 5
}
}
1. Synthesize answer (don't just list chunks)
2. Cite sources with emojis
📕 [Book Title, p.45, ¶3]3. Show similarity scores (optional, if useful)
4. Keep original query context
User: "What does Graeber say about the origins of money?"
Librarian:
Graeber argues that money did NOT originate from barter (the myth Adam Smith popularized). Instead, credit and debt systems came first — people kept track of obligations long before coins existed. 📕 [Debt: The First 5000 Years, p.21, ¶2]
He traces debt back to ancient Mesopotamia (~3500 BCE), where temple administrators recorded loans in cuneiform tablets. Money as we know it (coins) only appeared around 600 BCE in Lydia. 📕 [Debt, p.40, ¶5]
Key insight: Debt is older than money. Markets emerged from moral obligations, not rational barter. 📕 [Debt, p.89, ¶1]
Sources:
- 📕 Debt: The First 5000 Years (David Graeber) - 3 passages
- Similarity: ⭐⭐⭐⭐⭐
NEVER invent answers. If system fails, STOP and tell user exactly what's wrong.
librarian indexFrom VISION.md: "Honest incompetence > false competence"
A broken skill that TELLS you it's broken is more trustworthy than one that invents plausible-sounding nonsense.
sentence-transformers, faiss-cpu, pypdf, ebooklibcd ~/.openclaw/skills/librarian
pip3 install -r requirements.txt
# Put books in books/ folder
mkdir -p books/chaos-magick books/finance
# Run indexer
python3 engine/scripts/index_library.py
# Verify indexes created
ls -la books/.topic-index.json books/.librarian-index.json
"No metadata found"
index_library.py firstbooks/.topic-index.json exists"No results" but book exists
"System broken"
pip3 list | grep sentencepython3 engine/scripts/research.py --helpArchitecture:
Sandwich pattern:
Why this works:
Last updated: 2026-02-20
Epic: v0.15.0 Skill as Protocol