Install
openclaw skills install @carlosdelfino/calibre-ebooksManage and query the local Calibre library through the Books API, using local Calibre/RAG helpers only when file resolution or semantic indexing is explicitly needed.
openclaw skills install @carlosdelfino/calibre-ebooksLocation: /skills/calibre-ebooks/SKILL.md from the OpenClaw workspace root.
Use this skill only to manage and query the local Calibre-backed Books API and, when needed, prepare books that already exist in the local Calibre library for semantic RAG.
Use the Books API for local catalog discovery, metadata, formats, covers, local file access, and library statistics.
http://host.docker.internal:6180http://host.docker.internal:6180/docshttp://host.docker.internal:6180/redochttp://host.docker.internal:6180/openapi.jsonscripts/books_api_client.pyDo not assume endpoint names or hardcode URLs. The Python API client books_api_client.py features a dynamic discovery and scoring engine that auto-resolves logical actions (like searching, detail lookup, downloading, covers, stats, health status, and uploading) to the actual active endpoints defined in the current OpenAPI specification (/openapi.json). For custom endpoints not covered by logical commands, use the find command to discover details dynamically.
Treat the skill directory as the sandbox for generated files skills/calibre-ebboks/tmp. Keep temporary book files, covers, exported local files, and derived artifacts inside skills/calibre-ebooks/tmp/ unless a runtime explicitly provides a safer
attachment path.
External paths from the sandbox workspace and internal paths inside the sandbox:
skills/calibre-ebooks/ - skill root; contains this SKILL.md, helper
scripts, server code, and temporary skill artifacts. Sandbox /workspace/skills/calibre-ebooks/scripts/ - command-line clients and small automation
helpers. Do not write exported files here. Sandbox /workspace/scripts/skills/calibre-ebooks/tmp/downloads/ - temporary local book/file exports meant
for attachment delivery when the user is authorized to access the local
Calibre library. Delete files here after the runtime confirms the
attachment was sent/read. Sandbox /workspace/tmp/downloads/.skills/calibre-ebooks/tmp/calibre-covers/ - temporary cover images meant for
MEDIA: attachment delivery. Delete files here after successful delivery. Sandbox /workspace/tmp/calibre-covers/skills/calibre-ebooks/tmp/ - general scratch area for this skill. It is safe
to create subdirectories here for short-lived generated artifacts. Sandbox /workspace/tmpagents/rapport-bibliotecario/memory/calibre-import-queue/ - manual import
queue for received book attachments. This is inside the OpenClaw workspace but
outside this skill directory; use it only for queued inbound attachments./api/downloads/queue - download queue endpoint to record and process missing books.External or mapped paths and services:
BOOKS_API_URL - optional API base URL override for books_api_client.py.
If unset, the client uses http://host.docker.internal:6180.http://host.docker.internal:6180 - Books API as seen from containerized
runtimes. It is an internal service address, not a user-facing link.LOG_DIR - external server log directory when configured by the server. Do
not expose it in normal user-facing replies./skill/calibre-books/tmp/... - operating-system temporary space. Use only for ephemeral local
experiments. Prefer skills/calibre-ebooks/tmp/... for files that may need to
be attached, inspected, or cleaned by the skill.Run commands from the OpenClaw workspace root:
python3 /skills/calibre-ebooks/scripts/books_api_client.py --help
Or run from inside the skill directory:
cd /skills/calibre-ebooks
python3 scripts/books_api_client.py --help
Configuration precedence:
--base URL command-line option.BOOKS_API_URL environment variable loaded from the shell or .env.http://host.docker.internal:6180.The client reads .env files from these locations, in order, without
overwriting variables already set in the environment:
/skills/calibre-ebooks/scripts/.env/skills/calibre-ebooks/.env.envCommand syntax:
python3 /skills/calibre-ebooks/scripts/books_api_client.py [--base URL] COMMAND [ARGS...]
Global option:
--base URL - override BOOKS_API_URL and the default Books API URL for this
invocation.To support seamless gateway evolution, the client automatically discovers and maps the best-fitting active endpoints and parameters from the API's OpenAPI specification at runtime. Prefer these commands to avoid hardcoding routes:
docs - print Swagger UI, ReDoc, and OpenAPI JSON URLs for the selected API base.openapi - fetch and print the current OpenAPI JSON document.paths - summarize available API paths with methods, operation IDs, path parameters, and query parameters.find KEYWORD - search the OpenAPI schema for paths, operation IDs, or summaries matching a keyword. Use this to discover new custom endpoints.search QUERY [--limit N] - dynamically discovers the catalog search endpoint and executes search (catalog first, semantic fallback on server).semantic QUERY [--limit N] [--threshold VALUE] - dynamically discovers the semantic/RAG search endpoint (POST or GET) and maps query, limit, and similarity threshold parameters.book BOOK_ID - dynamically discovers the book detail endpoint and fetches metadata.download BOOK_ID [--output PATH] [--output-dir DIR] [--format FMT] [--check-virus] - dynamically discovers the book file retrieval/download endpoint and downloads the book.cover BOOK_ID [--output PATH] [--output-dir DIR] - dynamically discovers the cover image retrieval endpoint and downloads the cover.stats - dynamically discovers the library/RAG statistics endpoint and fetches metrics.status - dynamically discovers the health/database status endpoint and retrieves diagnostic status.upload FILE [--check-virus] - dynamically discovers the book upload endpoint and uploads the local file using multipart form-data.request METHOD PATH [--query KEY=VALUE ...] [--body JSON] [--output PATH] [--output-dir DIR] - fallback command to call an explicit endpoint when needed.Show documentation URLs:
python3 /skills/calibre-ebooks/scripts/books_api_client.py docs
Fetch the current OpenAPI specification:
python3 /skills/calibre-ebooks/scripts/books_api_client.py openapi
List available API paths with methods and parameters:
python3 /skills/calibre-ebooks/scripts/books_api_client.py paths
Search for endpoints matching a keyword (e.g. "enrich"):
python3 /skills/calibre-ebooks/scripts/books_api_client.py find "enrich"
Flexible catalog-first search, with semantic fallback handled by the server:
python3 /skills/calibre-ebooks/scripts/books_api_client.py search "termo ou titulo" --limit 10
Search embedded/RAG content through the Books API:
python3 /skills/calibre-ebooks/scripts/books_api_client.py semantic "pergunta ou tema" --limit 10 --threshold 0.3
Get book details by ID using endpoint discovery from OpenAPI:
python3 /skills/calibre-ebooks/scripts/books_api_client.py book 123
Check formats currently available for a book:
python3 /skills/calibre-ebooks/scripts/books_api_client.py request GET /api/books/123/formats
Save a book cover image dynamically:
python3 /skills/calibre-ebooks/scripts/books_api_client.py cover 123 --output-dir /skills/calibre-ebooks/tmp/calibre-covers
external folder: skills/calibre-ebooks/tmp/calibre-covers
Get library and RAG summary statistics:
python3 /skills/calibre-ebooks/scripts/books_api_client.py stats
Select a random book from the API catalog when the OpenAPI spec exposes a pagination/list endpoint:
# First find the list/books endpoint:
python3 /skills/calibre-ebooks/scripts/books_api_client.py find "books"
# Then run request on the discovered path:
python3 /skills/calibre-ebooks/scripts/books_api_client.py request GET /api/books --query limit=1000
Call an explicit endpoint after inspecting OpenAPI:
python3 /skills/calibre-ebooks/scripts/books_api_client.py request GET /books --query q=python --query limit=10
python3 /skills/calibre-ebooks/scripts/books_api_client.py request GET /books/123
python3 /skills/calibre-ebooks/scripts/books_api_client.py request POST /search --body '{"query":"python","limit":10}'
Save a file response dynamically:
python3 /skills/calibre-ebooks/scripts/books_api_client.py download 123 --output-dir /skills/calibre-ebooks/tmp/downloads
python3 /skills/calibre-ebooks/scripts/books_api_client.py download 123 --format EPUB --output-dir /skills/calibre-ebooks/tmp/downloads
external folder skills/calibre-ebooks/tmp/downloads
When downloading a book, the dynamically resolved endpoint returns the selected available Calibre format with the X-Book-Format header. If a specific format (e.g. PDF or EPUB) is desired, supply the --format option.
Before delivering a file to a user, check the book details or
/api/books/{id}/formats and confirm which formats are available. If the user
wants a format that is not listed, ask whether they want conversion and mention
that it may take a few minutes. Use the calibre-converter skill to request the
conversion. After conversion succeeds, download the requested format with:
python3 /skills/calibre-ebooks/scripts/books_api_client.py download 123 --format EPUB --output-dir /skills/calibre-ebooks/tmp/downloads
For local file exports meant to be sent as attachments to an authorized user,
save them in /skills/calibre-ebooks/tmp/downloads; externally this maps to
skills/calibre-ebooks/tmp/downloads/. Use --output-dir so the API-provided
complete filename is preserved. After the attachment is sent and the runtime has
confirmed the upload/read, delete the temporary copy to avoid accumulating book
files in the workspace. Never delete files from the Calibre library itself.
If BOOKS_API_URL is set, the client uses it instead of
http://host.docker.internal:6180. You can also pass --base URL.
books_api_client.py paths or openapi before making specific API
calls unless the exact endpoint has already been confirmed in this session.books_api_client.py request with the exact method and path from OpenAPI.Before starting a Calibre sync, when health status reports degraded status, or when
the Books API returns calibre_metadata_db_unavailable, diagnose the configured
CALIBRE_DB_PATH through:
python3 /skills/calibre-ebooks/scripts/books_api_client.py status
The diagnostic response includes:
status: available or unavailablereason: stable machine-readable cause such as file_missing,
database_locked, not_sqlite_database, invalid_calibre_schema,
integrity_check_failed, open_failed, or filesystem_errormessage: human-readable technical reasonagent_action: proceed, wait, or notify_usercalibre_db_path: the configured path being checkeddetails: optional evidence such as missing tables, size, mtime, or book
countAgent behavior:
agent_action is proceed, continue with the requested catalog/sync
operation.agent_action is wait, do not alarm the user immediately. Wait briefly
and retry; this usually means SQLite is temporarily locked or busy.agent_action is notify_user, treat the Calibre base as unsuitable for
handling until the user fixes it. In internal notes include the diagnostic
reason and message. In normal user-facing book replies, keep local paths
and raw server details private unless the user asked for technical debugging.Every book question should help the group conversation continue. Treat local availability as one part of the answer, not as the whole answer. Prefer a fluid paragraph or two over checklist-style replies.
Never use tables, use list bullets
When a user asks about a book, author, genre, topic, edition, or reading path:
For a missing book, the visible reply should usually flow like this:
Do not tell the group that the item was written to the download queue, logs, or any other internal file. The public wording is only that Carlos Delfino was informed about the absence.
Example missing-book voice:
The book you mentioned is interesting because it enters a discussion about memory, identity, and how personal experience shapes our choices. It is not in the local library yet, but you can usually find it through lawful channels such as Amazon, Google Books, or the publisher. I have informed Carlos Delfino about the absence; he will try to find it. If you want, I can search the local collection for something in the same line while you wait.
Avoid dead-end replies such as only saying that the title is missing, only listing IDs, mentioning internal memory/logging, or ending with a bare operational status.
If the user asks for references, sources, links, or where the cited information
came from, add a final References section to the visible reply.
In that section:
local Calibre library and expose only user-safe details such as title, author, id, and
formats.Recommended shape:
References
- Google Books: volume page consulted for title, author, publisher, and synopsis. <confirmed link>
- Publisher: official page consulted for description and edition data. <confirmed link>
Treat API URLs, server addresses, ports, OpenAPI paths, schema names, command lines, exit codes, filesystem paths, environment variables, timeout/connection errors, service-credit errors, and dependency diagnostics as internal instrumentation. Do not include those details in a user-facing reply unless the user explicitly asks for a technical/debug answer.
When a catalog/API/local lookup fails, do not list the failed services, commands, ports, URLs, paths, or raw errors. Reply in library language:
Do not end a normal book request by asking the user to restart services, run commands, wait for ports, or retry the API. Offer a useful next step instead: alternatives already confirmed in the local catalog, or a note that the item was registered for later review.
Some Calibre and RAG operations can take several minutes, especially indexing, semantic search over a large collection, attachment processing, and metadata enrichment.
When an operation may take longer than 2 minutes:
If the only available implementation is a single long blocking command, do not claim that live progress messages are possible from the agent while that command is running. Use a queued/background mode or a command that writes/checkpoints status so the agent can poll and update the group every 120 seconds.
When asked for counts such as indexed books, authors, publishers, categories, RAG chunks/excerpts, embedding model, chunk size, or overlap, call:
python3 /skills/calibre-ebooks/scripts/books_api_client.py stats
Trigger this workflow for questions like:
The endpoint returns:
indexed_booksauthorspublisherscategoriescataloged_topicslibrary_statusrag.chunks_excerptsrag.embedding_modelrag.chunk_sizerag.overlapusage.total_registered_requestsusage.most_requested_booksusage.latest_requested_bookFor user-facing replies, answer in English with a compact status summary.
Use cataloged_topics when the user asks about topics. Use
library_status when the user asks for overall library status. For broad
questions about the library situation, state, condition, or general information,
treat them as library status requests and include catalog/RAG statistics plus
usage statistics when available: top 5 requested books and latest requested
book. Do not expose raw JSON, OpenAPI paths, local URLs, endpoint names, command
exit codes, or server parameters unless the user explicitly asks for technical
details.
When the user asks for a book cover, or when a recommendation would benefit from the cover, use the Books API cover endpoint after identifying the book id.
Workflow:
/skills/calibre-ebooks/tmp/calibre-covers/; externally this maps to
skills/calibre-ebooks/tmp/calibre-covers/--output-dir so the API filename is used, or a deterministic filename
such as book-123-cover.jpg when an explicit path is required.MEDIA: directive on its own line:
MEDIA:skills/calibre-ebooks/tmp/calibre-covers/book-123-cover.jpg/skills/calibre-ebooks/tmp/calibre-covers/.When the user asks for a specific book by title, do not stop after a failed catalog/title search.
python3 /skills/calibre-ebooks/scripts/books_api_client.py search "provided title" --limit 10result_type: catalog means confirmed local
book metadata, while semantic means a RAG/content match and should be
presented as a related excerpt, not as an exact title match unless metadata
confirms it.python3 /skills/calibre-ebooks/calibre-openclaw-server/scripts/document_semantic_rag.py --search "provided title" --jsonpython3 /skills/calibre-ebooks/scripts/books_api_client.py queue "title" --author "author" [other options]. This will
record the request on the server so Carlos Delfino or the system can retrieve it later.Alternative suggestions should include:
When someone sends a book file in the configured WhatsApp group, accept only book-like attachments in formats supported by the Calibre workflow, preferably PDF, EPUB, AZW3, MOBI, DjVu, TXT, RTF, or DOCX, for manual import review.
Workflow:
memory/calibre-import-queue/files/memory/calibre-import-queue/index.mdwaiting for manual import.The import queue lives in the Rapport Bibliotecario agent workspace:
agents/rapport-bibliotecario/memory/calibre-import-queue/
When the user asks for a book suggestion, a random book, "recommend me a book", or any generic book request without a specific title/author/topic, first try to provide one book from the Calibre library. For topic-based recommendations such as "recommend me a book about Python and digital twins", search the local library first with the topic terms and reasonable variants. If no local result is confirmed, say that the local library does not currently have a clear match and, when possible, suggest nearby alternatives already present in Calibre. You may also suggest consulting Google Books or Amazon Books for public catalog/store information about titles that are not in the local library.
When the user says "good night", "good night everyone", "I am going to sleep", "see you tomorrow", or another night-time farewell, treat it as a light recommendation opportunity, not as a normal generic random-book request.
Response goals:
books_api_client.py queue)
so it can be obtained later. Do not tell the group about memory, files, queues, logs, or
internal registration.Example:
Good night. To close the day lightly, I would suggest The Little Prince, by Antoine de Saint-Exupery: it is a brief, luminous read, good for remembering friendship, care, and simplicity before sleeping. This one is not in the local library yet, but I have informed Carlos Delfino so he can try to find it. May the reading be short and sleep come gently.
Preferred API workflow:
books_api_client.py find "books" or paths unless it is already known in this session./api/books, run python3 /skills/calibre-ebooks/scripts/books_api_client.py request GET /api/books --query limit=1000).books array.If the API is unreachable or does not expose enough catalog items, use the read-only local fallback:
python3 /skills/calibre-ebooks/calibre-openclaw-server/scripts/calibre_query.py --db "$CALIBRE_METADATA_DB" random
Do not repeatedly return the first item from a list. The selection must be randomized for each request.
Do not include local server/API/file links such as localhost, 0.0.0.0,
127.0.0.1, host.docker.internal, /api/books/..., file://, or filesystem paths. Those links are
not valid for group members outside the server. If access is needed, say that
the book is available in the Calibre library and provide only the book id,
title, authors, and formats so the librarian/admin can locate it.
Recommended response shape for random suggestions:
Book: title and id.Author(s): authors from metadata.Publisher and year: publisher and publication year when available; say
not provided only when metadata is missing.Formats: available file formats.Synopsis: three to five short sentences based on Calibre
comments/description, enough for a reader to understand what the book is
about.Main themes: two to four concrete themes covered by the book.Why read it: one or two practical reasons why the recommendation is
relevant.Context: who should read it, what problem/topic it helps with, and when it
is useful.Access: mention that it is in the Calibre library by id/formats; do not add
local or server-only links.id, title, authors, and formats when there are multiple book matches.books_api_client.py search; the server handles
catalog-first search and semantic fallback. Treat result_type=semantic as a
related excerpt/match, not as confirmed availability of the requested exact
title. Use books_api_client.py semantic or document_semantic_rag.py --search
only for explicit RAG/content testing or local RAG maintenance.document_semantic_rag.py --check --json reports missing dependencies,
keep exact dependency diagnostics internal unless the user asked for technical
debugging. For normal users, say only that semantic analysis is unavailable
right now and continue with local catalog options.citation field, use it as the
citation base. Do not answer from memory when a RAG excerpt is available for
the same claim.Para fazer fetch simples, use o curl, só se der erro então use outros skills.