For tools and coding agentslibrary-hub-api.d.tsapi.json
LibraryHubApi
version
readonly version: string
Semantic version of this API. Check it with isCompatible (or use getLibraryHub).
listBooks
listBooks(which: BookRef[] | {
shelf: string;
} | {
ids: BookRef[];
} | "all"): Promise<BookSummary[]>Books (in the order asked), or a shelf's books. Works from the Content Server, or read-only from the library file when the server is off and a library folder is set. Rejects with book-missing naming any id Calibre doesn't have. { ids } works as the list does. Any BookRef that names a Calibre book; one that names another book rejects with not-calibre. 'all': every book in Calibre, by id.
bookFile
bookFile(book: BookRef, format: BookFormat, opts?: BookFileOptions): Promise<ArrayBuffer | null>
A book file's bytes, from the Content Server, else read-only from the library folder when the server is off. With { convert: true }, an EPUB the book lacks is made from its AZW3 or MOBI after the user agrees (null if they decline); that needs the server, and rejects with server-off without it. the book is any BookRef: a book file in the vault, or one another provider holds, is served as it is.
pdfText
pdfText(book: BookRef, pages?: PageRange): Promise<string>
A PDF's text, page by page (pages separated by a blank line), through Obsidian's PDF.js. With pages, only those pages, so a long book can be read a part at a time. the book is any BookRef, and the text is laid out: a line of the page on a line of its own, a wider gap a blank line, a word broken at a line's end joined. chars a-b locations and bookText count in this text.
shelfMembers
shelfMembers(shelf: string): Promise<number[]>
The Calibre ids of the books on a shelf, ascending: in shelves, not in shelves_exclude (the same test as the shelf's Base). A shelf is named by its shelf_id, or its note's name or path. Book notes without a calibre_id aren't included.
calibreChecks
calibreChecks(): Promise<CalibreChecks>
The Calibre settings Library Hub depends on, checked against the Content Server now: that it answers, that any login works, that the library exists, and that it allows changes (needed to convert a book or write to it). Each check that fails says how to set it right in Calibre. Never rejects: a server that doesn't answer is a failed check.
listShelves
listShelves(): Promise<ShelfInfo[]>
Every shelf, by name, with how many Calibre books are on it.
shelfBaseQuery
shelfBaseQuery(shelf: string): Promise<ShelfBaseQuery>
A shelf's membership as Bases reads it, with the shelf's values filled in: a one-line filter for your own Base or formula, and a whole .base file.
addToShelf
addToShelf(shelf: string, books: BookRef[]): Promise<ShelfChange>
Puts books on a shelf: each book's note gets the shelf in shelves and any exclusion is lifted. Books already on it are unchanged; books without a note are noNote. Logged as one run (run) you can pass to undoRun; nothing is logged when nothing changed.
removeFromShelf
removeFromShelf(shelf: string, books: BookRef[]): Promise<ShelfChange>
Takes books off a shelf: each book's note drops it from shelves and excludes it (shelves_exclude), so nothing puts the book back by itself. Books not on it are unchanged. Logged as one run; nothing when nothing changed.
createShelf
createShelf(spec: NewShelf): Promise<CreatedShelf>
Makes a shelf: a shelf note in the shelves folder (with Shelf Members.base beside it the first time) and the given books pinned to it, in one run. A shelf whose shelf_id exists already is returned as it is, with the books added, so asking twice makes one shelf.
renameShelf
renameShelf(shelf: string, name: string): Promise<RenamedShelf>
Renames a shelf's note and heading; its shelf_id stays, so nothing that names the shelf breaks. Undoable.
deleteShelf
deleteShelf(shelf: string): Promise<DeletedShelf>
Deletes a shelf: the note goes to the trash and its id comes out of every book note. undoRun brings it all back.
mergeShelves
mergeShelves(shelves: string[]): Promise<MergedShelves>
Merges shelves into the first one named: every book on the others is pinned to it, then the others are deleted, in one run. Needs two or more different shelves.
suggestShelves
suggestShelves(book: BookRef, limit?: number): Promise<ShelfSuggestion[]>
The shelves that suit a book, best first: every shelf it isn't on, ranked by Topic Map by what the book and each shelf's books are about. No model is asked. limit is 5 unless given (1–50).
Topic Map serves this: without it, or with one that doesn't rank shelves yet, it rejects with needs-topic-map; when Topic Map hasn't indexed the book, with no-vectors.
undoRun
undoRun(run: string): Promise<UndoReport>
Undoes a run a write operation returned: fields go back unless they changed since (those are named in kept), files the run made go to the trash. A run already undone restores nothing, so undoing twice is safe.
openBook
openBook(book: BookRef, at?: BookPlace): Promise<OpenedBook>
Opens a book in Library Hub's reader, in a new tab, at a place. The book is any BookRef (A Calibre id). Rejects book-missing (nothing matches, or the book has no note) and format-missing (no EPUB, AZW3, MOBI or PDF to read; an AZW3 or MOBI, opened when the book has no EPUB, before its PDF).
findBook
findBook(book: BookRef): Promise<FoundBook>
The book a reference names (see BookRef), without opening it. Rejects book-missing, saying what it tried.
onBooksChanged
onBooksChanged(cb: (change: BooksChanged) => void): () => void
Calls cb each time books arrive, change or go (see BooksChanged); the same news as the library-hub:books-changed workspace event. Returns the function that stops it: pass it to your plugin's register().
shelvesOf
shelvesOf(books: BookRef[]): Promise<BookShelves[]>
Which shelves each book is on, in the order asked: in shelves, not excluded (the same test as shelfMembers). A book without a note is on none.
findBooks
findBooks(query: string, limit?: number): Promise<BookSummary[]>
Books whose title and authors hold every word of query (case and accents ignored), titles that start with it first. limit is 10 unless given (1–50).
estimateShelfFromDescription
estimateShelfFromDescription(spec: DescribedShelf): Promise<ShelfEstimate>
What making a shelf from a description would read and cost: how many books the model would read and in how many calls through library-hub.shelf-keep. No model is asked. Rejects with no-hub without Model Hub.; the books are those that share the description's words (no vectors needed).
shelfFromDescription
shelfFromDescription(spec: DescribedShelf): Promise<DescribedShelfResult>
Makes a shelf from a description: the books that best match its words (title, authors and context, by a keyword ranking), and any naming a term, are read by library-hub.shelf-keep, which keeps those that belong; the shelf is made with them pinned, in one logged run that undoRun takes back. A shelf of that name already there gets the books added. By words (before, the books nearest it by meaning).
estimateSummary
estimateSummary(book: BookRef, kind?: SummaryKind): Promise<SummaryEstimate>
What summarizing a book would read and cost. Reads the book's text; no model is asked. kind is summary unless given.
summarizeBook
summarizeBook(book: BookRef, kind?: SummaryKind): Promise<StartedJob>
Summarizes a book in the background, as the plugin's own commands do (the job shows in the Library panel), and resolves at once with the job and its run. summary writes a one-page ## Summary in the book's note; chapters writes one note per chapter (quotes checked word for word) and a ## Chapters list. Follow it with jobStatus; undoRun takes it back.
jobStatus
jobStatus(job: number): Promise<JobInfo>
A background job's progress, cost and outcome. Rejects with job-missing for an id it doesn't know.
bookText
bookText(book: BookRef, opts?: BookTextOptions): Promise<BookText>
A book's text as chapters, read from its file: the EPUB, else the AZW3 or MOBI as it is, else the PDF, laid out, with its outline's chapters. An AZW3 or MOBI that can't be read as it is (DRM, a damaged file) is read from an EPUB Calibre makes from it, with convert. Each chapter has a location openBook lands on, its offsets in the whole text and its text; hash changes only when the text does. A Calibre book is read from the Content Server, else from the library folder, where nothing can be converted: an unreadable AZW3 or MOBI with a PDF rejects with needs-conversion (with convert, its PDF is read, with a warning), and one without rejects with server-off. A book file in the vault, or one another provider serves, is read as it is. Rejects with book-missing, format-missing (no EPUB, AZW3, MOBI or PDF), needs-conversion, declined, conversion-failed and no-text (a scan, a book of images, a file that can't be read).
bookChapters
bookChapters(book: BookRef, opts?: BookTextOptions): Promise<BookChapters>
The same as bookText without the chapters' text: a book's chapters, their locations and offsets, and the text's hash. It reads the whole file all the same.
status
status(): Promise<LibraryStatus>
Whether Calibre's Content Server and the providers turned on can be reached now, and what the library holds. Never rejects: something that doesn't answer is reported as such. Asks Calibre once and each provider's checks (each given a few seconds).
Functions
isCompatible
declare function isCompatible(actual: string, wanted: string): boolean;
True when a consumer built against wanted can use an API at actual: same major and a minor at least as new. Before 1.0, minors break by default, so a 0.x API serves only the minors it promises (0.1 and up). The same rule, word for word, as Model Hub's (@insurgently/model-hub-api), used for both directions.
getLibraryHub
declare function getLibraryHub(app: unknown, wanted: string, opts?: {
by?: string;
for?: string;
}): GetLibraryHubResult;Finds Library Hub in this vault and checks its API version against the one you built for (isCompatible). opts.by names your plugin and opts.for what it needs books for, in the message: getLibraryHub(app, '0.8.0', { by: 'My Plugin', for: 'for book collections' }).
hasMethod
declare function hasMethod<K extends keyof LibraryHubApi>(api: LibraryHubApi, name: K): api is LibraryHubApi & Required<Pick<LibraryHubApi, K>>;
Whether this Library Hub has a method newer than the version you gate on: if (hasMethod(libraryHub, 'bookText')) …. Methods tagged @since a later version than your gate may be missing on an older Library Hub.
onLibraryHubReady
declare function onLibraryHubReady(app: unknown, plugin: {
registerEvent(ref: unknown): void;
}, wanted: string, cb: (libraryHub: LibraryHubApi) => void): void;Runs cb with the API now if Library Hub is loaded (and compatible with wanted), and again each time it loads: it fires library-hub:ready on the workspace at the end of its onload. The listener is registered through plugin.registerEvent, so it stops when your plugin unloads.
onLibraryHubReady(this.app, this, '0.8.0', (libraryHub) => (this.libraryHub = libraryHub));
getBooks
declare function getBooks(app: unknown, wanted: string): GetBooksResult;
onBooksReady
declare function onBooksReady(app: unknown, plugin: {
registerEvent(ref: unknown): void;
}, wanted: string, cb: (books: LibraryHubApi) => void): void;Constants
BOOKS_API_VERSION
declare const BOOKS_API_VERSION: string;
BOOKS_PLUGIN_ID
declare const BOOKS_PLUGIN_ID = "library-hub";
BOOKS_READY_EVENT
declare const BOOKS_READY_EVENT = "library-hub:ready";
BOOKS_TOOLS
declare const BOOKS_TOOLS: LibraryHubTool[];
LIBRARY_HUB_API_VERSION
declare const LIBRARY_HUB_API_VERSION: string;
Semantic version of Library Hub's public API. Consumers check it before calling anything else.
LIBRARY_HUB_BOOKS_CHANGED_EVENT
declare const LIBRARY_HUB_BOOKS_CHANGED_EVENT = "library-hub:books-changed";
The workspace event Library Hub fires when books arrive, change or go, with a BooksChanged. onBooksChanged in the API hears the same thing.
this.registerEvent(this.app.workspace.on(LIBRARY_HUB_BOOKS_CHANGED_EVENT, (c: BooksChanged) => reindex(c.added)));
LIBRARY_HUB_PLUGIN_ID
declare const LIBRARY_HUB_PLUGIN_ID = "library-hub";
LIBRARY_HUB_READY_EVENT
declare const LIBRARY_HUB_READY_EVENT = "library-hub:ready";
The workspace event Library Hub fires each time it loads, with its API: at startup, and when the user disables and enables it again. onLibraryHubReady listens for it.
LIBRARY_HUB_TOOLS
declare const LIBRARY_HUB_TOOLS: LibraryHubTool[];
Every operation as a tool (see LibraryHubTool).
Types
Open a type to see its members.
BookChapter interface
One chapter of a book, as bookChapters lists it. An EPUB's, AZW3's or MOBI's chapters are its contents entries (an EPUB's nav or NCX), every one (front and back matter left out; never merged, however many), a file split at its entries' anchors when several point into it, and a file no entry claims a chapter of its own. A PDF's chapters are its outline's entries, or 12 even parts when it has no outline.
interface BookChapter
n: number1-based, in reading order. For a book of 30 chapters or fewer,
openBook(book, { chapter: n })opens at it; past 30 the chapter notes (and soopenBook'schapternumber) count merged parts, so open atlocation.title: stringlocation: stringWhere it starts, as
openBook'sBookPlace.locationtakes it: an EPUB's file inside the book (OEBPS/c3.xhtml, orOEBPS/all.xhtml#ch3for a chapter that starts inside a file); an AZW3's or MOBI's contents entry (kindle:pos:fid:0001:off:0000000000,filepos:0000001234), or the start of its section as a CFI (epubcfi(/6/4!/4)) when no entry points there; orchars a-bfor a PDF (code points into its text, which give the page). A passage inside the chapter keeps the chapter's location (EPUB, AZW3, MOBI) or adds its own offset tostart(PDF).start: numberWhere it starts and ends in the book's whole text, in code points (as a corpus counts them).
end: number
BookChapters interface
A book's chapters, as bookChapters gives them.
interface BookChapters
book: FoundBookThe book the reference named.
format: BookFormat | "AZW3" | "MOBI"The file the text was read from.
AZW3andMOBI: such a file is read as it is, with no conversion.convertedFrom?: "AZW3" | "MOBI"When the EPUB was just made from the book's AZW3 or MOBI (
convert, for one that can't be read as it is), which.hash: stringSHA-256 of the book's whole text (UTF-8), in hex. It changes only when the text does, so a corpus can keep its passages while it matches. The whole text is an EPUB's spine files' text in reading order (an AZW3's or MOBI's sections; front and back matter included), or a PDF's pages as
pdfTextgives them, joined by blank lines. A page's paragraphs and blocks are separated by a blank line, its line breaks by a line break. an EPUB is read with foliate-js, the reader's own parser, so every EPUB's text, andhash, changed once in 0.9.length: numberThe whole text's length, in code points.
chapters: BookChapter[]warnings: string[]What a reader of the text should know, in plain words: a PDF with no outline cut into even parts, a conversion declined.
outline: booleanWhether the chapters follow the book's own structure: an EPUB's contents, or a PDF's outline. False for a PDF with no outline, cut into even parts (or one part when short).
BookFileOptions interface
interface BookFileOptions
convert?: booleanFor an EPUB the book doesn't have: when it has an AZW3 or MOBI, ask the user to convert it in Calibre. The conversion adds an EPUB to the book in their Calibre library, so the user is always asked first;
bookFileresolvesnullwhen they decline. Without this, a missing EPUB rejects withformat-missing. Converting needs Calibre's Content Server: with only the library folder, it rejects withserver-off.
BookFormat type
The formats bookFile returns. Other formats (AZW3, MOBI…) are listed in formats but not served.
type BookFormat = "EPUB" | "PDF";
BookPlace interface
Where in a book to open it. Tried in order: highlight, quote, location, chapter, href, then page; the first that lands wins.; chapter, highlight and location.
interface BookPlace
href?: stringA contents entry's
file#anchor(an EPUB section), as in the book's table of contents or spine.quote?: stringA short verbatim passage from the book (a sentence or so); the reader finds it and shows it, highlighted if it can. Whitespace and quote-mark differences are ignored.
page?: numberA 1-based page number (PDFs).
chapter?: string | numberA chapter: its title (as the contents has it; case and spacing don't matter), or its number counted the way Library Hub's chapter notes count them (front and back matter left out).
highlight?: stringA highlight's id (
h_…) in the book's highlights note: the reader goes to it, checking its text first.location?: stringA passage's location exactly as a corpus records it (Topic Map's
location): an EPUB contents entry (text/c3.xhtml#s2), an AZW3 or MOBI one asbookChaptersgives it (kindle:pos:…,filepos:…, a section'sepubcfi(…);), orchars a-b, code-point offsets intopdfText's text, which gives the PDF page. What a split adds after it (§2,w3) is ignored. Pass the passage'squotewith it to land on the passage itself.
BookRef type
Which book: one thing another plugin, a link or a corpus knows about it. (0.5 took a Calibre id only).
- a number, or a string of digits: a Calibre id (ten or thirteen digits that check out as an ISBN are an ISBN); - a book note's path or name, or a link to it ([[Name]]); - a book file's path: a file in the vault (opened as it is, with or without a note), or a path inside a Calibre library, whose book folder Title (42) names the Calibre id; - an ISBN (10 or 13 digits, hyphens allowed), a Calibre uuid, an Audiobookshelf id or an OPDS id.
A string can say which with a prefix: calibre:42, note:Books/Library/Salt Roads.md, file:…, isbn:…, uuid:…, audiobookshelf:…, opds:…. The object form names one: { isbn: '978…' }.
type BookRef = number | string | BookRefParts;
BookRefParts interface
A book reference that names what it is (see BookRef): exactly one of these.
interface BookRefParts
calibre?: numbernote?: stringfile?: stringisbn?: stringuuid?: stringaudiobookshelf?: stringopds?: string
BooksApi type
type BooksApi = LibraryHubApi;
BooksChanged interface
Books that arrived, changed or went. Changes close together come as one: a sync of two hundred books is one event.
interface BooksChanged
added: ChangedBook[]New book notes: from a notes sync, a resync or Bring in new books.
changed: ChangedBook[]Book notes a sync changed, and notes renamed or moved (with
previousPath).removed: ChangedBook[]Book notes deleted (or moved out of the library folder).
source: "sync" | "intake" | "vault"What did it: a notes sync or resync (
sync), Bring in new books (intake), or an edit in the vault (vault).
BooksErrorCode type
type BooksErrorCode = LibraryHubErrorCode;
BookShelves interface
Which shelves a book is on, as shelvesOf gives it.
interface BookShelves
id: numberThe Calibre id asked about.
notePath: string | nullThe book's note, or null when it has none: membership lives in the note, so such a book is on no shelf.
shelves: string[]The
shelf_ids of the shelves it is on (inshelves, not excluded), ascending.
BooksTool type
type BooksTool = LibraryHubTool;
BookSummary interface
One Calibre book, as listBooks gives it.
interface BookSummary
id: numberThe Calibre id.
title: stringauthors: string[]formats: string[]Calibre's formats for the book, upper case:
EPUB,PDF,AZW3…notePath: string | nullThe book's note in the library folder (by its
calibre_idorcalibre_ids), or null when it has none.context?: stringWhat the book is about, as plain text: the note's
contextfield, else Calibre's comments with their HTML taken out. Absent when neither has any.
BookText interface
A book's text, as bookText gives it: bookChapters with each chapter's text.
interface BookText extends BookChapters
chapters: BookTextChapter[]
BookTextChapter interface
A chapter with its text: exactly the book's whole text from start to end.
interface BookTextChapter extends BookChapter
text: string
BookTextOptions interface
What bookText and bookChapters take.
interface BookTextOptions
convert?: booleanFor a book whose only text is an AZW3 or MOBI that can't be read as it is (DRM, a damaged file): ask the user to convert it to an EPUB in Calibre (it adds a file to their library, so they are always asked). Without it, such a book rejects with
needs-conversion, naming the cause. If they decline, or the conversion fails, a PDF is read instead when the book has one (with a warning); else the call rejects withdeclinedorconversion-failed. an AZW3 or MOBI that can be read is read as it is, so this only matters when it can't.
CalibreCheck interface
One Calibre setting as checked.
interface CalibreCheck
id: "server" | "login" | "library" | "changes"name: stringThe setting in a word or two: "Content Server", "Login", "Library", "Changes".
state: CalibreCheckStateoff: not checked, because an earlier check failed.text: stringWhat was found.
fix?: stringWhere to set it right in Calibre, when
stateisbad.
CalibreChecks interface
interface CalibreChecks
ok: booleanEvery check passed.
reads: booleanThe server answers and the library exists: books can be read.
writes: booleanThe server allows changes.
checks: CalibreCheck[]
CalibreCheckState type
type CalibreCheckState = "ok" | "bad" | "off";
CalibreStatus interface
Calibre, as status finds it.
interface CalibreStatus
state: "server" | "file" | "off"server: the Content Server answers, so books, their files and text can be read.file: the server is off and the library folder is read instead, read-only (books, and their files and text; no conversion).off: neither (not set up, or not answering).files: booleanBook files can be read now:
bookFile,pdfTextandbookTextof a Calibre book.text: stringWhat was found, in plain words.
ChangedBook interface
One book in a BooksChanged.
interface ChangedBook
notePath: stringThe book's note in the vault (for a removed book, where it was).
id: number | nullThe Calibre id, when the book has one (an audiobook only another provider holds has none).
title: stringThe title, from the note's name.
authors: string[]The author on the note, when it names one.
previousPath?: stringFor a note that was renamed or moved: where it was before.
CreatedShelf interface
What createShelf did.
interface CreatedShelf extends ShelfChange
shelf: ShelfInfocreated: booleanFalse when a shelf with that
shelf_idexisted already: it is returned as is, with the books added.
DeletedShelf interface
What deleteShelf did.
interface DeletedShelf
deleted: stringThe
shelf_idof the shelf that was deleted.unpinned: numberHow many book notes had the shelf taken out of them.
run: string | nullThe logged run, to pass to
undoRun, which brings the shelf note and every pin back.
DescribedShelf interface
What estimateShelfFromDescription and shelfFromDescription take.
interface DescribedShelf
name: stringThe shelf's name: its note's name and the source of its
shelf_id.description: stringWhat belongs on it, in a sentence or two. The books are chosen by this; it also becomes the note's summary.
terms?: string[]Names or places a member's title or description would mention: books naming one are considered too.
group?: stringA group folder under the shelves folder; without it, the packs choose.
DescribedShelfResult interface
What shelfFromDescription did.
interface DescribedShelfResult extends CreatedShelf
considered: numberHow many books the model read.
costUsd: numberWhat the calls cost, in US dollars.
Estimate interface
What a run that asks a model would read and cost, before it runs.
interface Estimate
role: stringThe role the calls go through:
library-hub.shelf-keep,library-hub.summarize,library-hub.chapters.calls: numberHow many model calls, at most.
tokens: numberAbout how many input tokens, in all.
usd: number | nullAbout what it costs, in US dollars. With Model Hub 0.13 or later, the high end of Model Hub's estimate of the calls (each with a full reply), so a budget set from it holds; null when Model Hub can't price them (
textsays why). With an older Model Hub, the input at the role's first model's listed price; null when that model has no price.text: stringThe same in one plain sentence, as the approval dialog shows it: with Model Hub 0.13 or later, a range ("about $0.02–$0.09").
FoundBook interface
The book a reference named, as findBook gives it.
interface FoundBook
notePath: string | nullThe book's note, or null for a book file in the vault that has none (or, a Calibre book named by its id that has no note yet).
calibreId: number | nullIts Calibre id, or null when it isn't a Calibre book (or the file was named directly).
file: string | nullThe book file in the vault, when the reference named one; null for a book read through its providers.
via: "calibre" | "note" | "file" | "isbn" | "uuid" | "audiobookshelf" | "opds"What matched:
calibre,note,file,isbn,uuid,audiobookshelforopds.
GetBooksResult type
What the deprecated getBooks answers: { books }, as before 0.6. getLibraryHub answers GetLibraryHubResult.
type GetBooksResult = {
books: LibraryHubApi;
} | {
books: null;
reason: "missing" | "incompatible";
message: string;
version?: string;
};GetLibraryHubResult type
What getLibraryHub answers: the API, or why not, in a message to show as it is.
type GetLibraryHubResult = {
libraryHub: LibraryHubApi;
} | {
libraryHub: null;
reason: "missing" | "incompatible";
message: string;
version?: string;
};JobInfo interface
A background job as jobStatus gives it.
interface JobInfo
job: numbername: stringstatus: "waiting" | "running" | "done" | "failed" | "cancelled"label: stringWhat it is doing now, or did last.
done: numberSteps done and in all (chapters, say), when it counts them; 0 when it doesn't.
total: numberspentUsd: numberWhat it has spent so far, in US dollars.
error?: stringWhy it failed, in plain words.
run?: stringIts logged run, when it has one.
JsonSchema interface
A JSON schema for a tool's input, as Model Hub's tool registry and MCP servers take it.
interface JsonSchema
type: "object" | "string" | "number" | "integer" | "boolean" | "array"description?: stringproperties?: Record<string, JsonSchema>required?: string[]items?: JsonSchemaenum?: string[]minimum?: number
LibraryHubErrorCode type
Why a call failed: - server-off: Calibre's Content Server isn't set or doesn't answer, and no library folder is set to read the library instead. With a library folder, books and their files are read from it, and only what changes Calibre needs the server: converting a book to EPUB rejects with server-off, saying so. - server-error: the server answered with an error (a login it asks for, a refused change, a failure). With the server off: a book file in the library folder that couldn't be read, such as one in a cloud-synced folder that isn't downloaded on this computer, or took too long to download; the message names the file. - book-missing: Calibre has no book with that id (for openBook and findBook: nothing matches the reference, or the book has no note; the message says what was tried). - format-missing: the book has no file in that format (and none to convert from, or convert wasn't asked); for openBook, no EPUB, AZW3, MOBI or PDF to read (AZW3 and MOBI). - shelf-missing: no shelf note has that id or name. - conversion-failed: Calibre tried to convert the book and couldn't. - no-text: the PDF has no text layer (a scan). - invalid-request: the arguments are malformed (an id that isn't a number, an unknown format). - no-vectors: the library has no book vectors yet, or this book has none. the vectors are Topic Map's: given when Topic Map hasn't indexed the library, or this book, yet. - no-hub: Model Hub isn't installed, enabled or new enough, and the call asks a model. - job-missing: no job has that id (finished jobs are kept for a while, the 30 most recent). - needs-conversion: bookText or bookChapters of a book whose only text is an AZW3 or MOBI that can't be read as it is (DRM, a damaged file; the message names the cause), without { convert: true }: making an EPUB adds a file to the user's Calibre library, so it is only done when asked. An AZW3 or MOBI that can be read is read as it is, with no conversion. - declined: the user declined that conversion, and the book has no PDF to read instead. - not-calibre: the call works on Calibre books, and the reference names a book Calibre doesn't hold (a book file in the vault, a book only another provider has). - busy: Obsidian is still updating links in the vault, so a change that moves a note (renameShelf) was not made. Nothing was changed; try again in a moment. also: with the server off, Calibre's library file was being written each time it was read (Calibre adding books); try again when it's done. - needs-topic-map: the call works from what books are about (their vectors), which Library Hub alone doesn't keep: it needs the Topic Map plugin, which serves it, or a newer Topic Map that offers the call. Also a Topic Map refusal with no code of its own here, its words in the message. Library Hub's own matching is by words.
no-text also covers an EPUB, AZW3 or MOBI with no readable text (a book of images), and a book file that can't be read at all (DRM, a damaged file), the message naming the cause.
type LibraryHubErrorCode = "server-off" | "server-error" | "book-missing" | "format-missing" | "shelf-missing" | "conversion-failed" | "no-text" | "invalid-request" | "no-vectors" | "no-hub" | "job-missing" | "needs-conversion" | "declined" | "not-calibre" | "busy" | "needs-topic-map";
LibraryHubTool interface
One operation as a tool a model can call. Library Hub registers these with Model Hub's tool registry when both load, so they run from the Hub's panel and its MCP server under the user's tool settings; anything else (a command palette, say) can map them the same way. method is the LibraryHubApi method to call; args names the input properties in the order the method takes them (a missing optional one is passed as undefined), or is the one entry $input for a method that takes the input object whole.
interface LibraryHubTool
name: stringDotted and unique:
library-hub.list_shelves.description: stringFor the model: what it does and when to use it.
input: JsonSchemamethod: keyof LibraryHubApiargs: string[]Input properties in the method's argument order; the one entry
$inputpasses the whole input object.effect: "read" | "write"Whether it changes anything. Model Hub runs reads freely and asks before a write, unless the user says otherwise.
estimate?: keyof LibraryHubApiA method that takes the same arguments and resolves to an
Estimate: what the call would read and cost, shown to the user before they approve it.
LibraryStatus interface
What Library Hub can reach and what the library holds, as status gives it.
interface LibraryStatus
version: stringThe API version (the same as
versionon the API).calibre: CalibreStatusproviders: ProviderStatus[]The providers turned on, other than Calibre, each checked.
library: { notes: number; calibreBooks: number | null; formats: Record<string, number>; shelves: number; }
MergedShelves interface
What mergeShelves did.
interface MergedShelves
shelf: ShelfInfoThe shelf that was kept, with its new member count.
merged: string[]The
shelf_ids of the shelves merged into it and deleted.changed: number[]Calibre ids whose notes now pin the kept shelf.
noNote: number[]Calibre ids with no book note, which could not be moved.
run: string | null
NewShelf interface
What createShelf takes.
interface NewShelf
name: stringThe shelf's name: its note's name, and the source of its
shelf_id("Field Guides" →field-guides).description?: stringA sentence for the note's summary.
books?: BookRef[]Books to pin to it now: Calibre ids, or any
BookRefthat names a Calibre book.rule?: stringA cluster id whose books belong to it by rule.
group?: stringA group folder under the shelves folder. Without it, the first pack group whose pattern matches the name.
OpenedBook interface
What openBook did.
interface OpenedBook
placed: "highlight" | "quote" | "href" | "chapter" | "page" | "start"Which part of the place it landed on; 'start' when none matched (the book opens where the reader would by default). A
locationlands as 'href' (its contents entry) or 'page' (its PDF page). 'chapter' and 'highlight' .
PageRange interface
A pages range for pdfText, 1-based and inclusive; either end may be left out.
interface PageRange
from?: numberto?: number
ProviderStatus interface
Another book provider (Audiobookshelf, OPDS, Readwise…) the user has turned on, as status finds it.
interface ProviderStatus
id: stringname: stringstate: "ok" | "bad"ok: its checks pass;bad: one failed, or it didn't answer in time.files: booleanWhether it can serve book files (so
bookTextcan read a book only it has).text: stringWhat was found, in plain words.
RenamedShelf interface
What renameShelf did.
interface RenamedShelf
shelf: ShelfInfoThe shelf under its new name; its
idis the same, so pins and Bases that name it still work.run: string | nullThe logged run, to pass to
undoRun; null when the shelf already had that name.
ShelfBaseQuery interface
A shelf's membership as a Bases filter.
interface ShelfBaseQuery
filter: stringOne line for a Base's
filtersor a formula: the shelf'sshelvesandshelves_excludetest with its id filled in.base: stringA whole
.basefile: the same filter and the plugin's three views (Shelf, Cards, Shelf table).
ShelfChange interface
What a write to shelf membership did.
interface ShelfChange
run: string | nullThe logged run, to pass to
undoRun; null when nothing changed, so there was nothing to log.changed: number[]Calibre ids whose notes changed.
unchanged: number[]Calibre ids already as asked (on the shelf for an add, off it for a remove).
noNote: number[]Calibre ids with no book note: membership lives in the note, so these can't be shelved until a sync makes one.
ShelfEstimate interface
What estimateShelfFromDescription gives.
interface ShelfEstimate extends Estimate
candidates: numberHow many books would be read by the model: those that best match the description's words, and those naming a term.
ShelfInfo interface
One shelf, as listShelves gives it.
interface ShelfInfo
id: stringThe shelf's
shelf_id(collection_idbefore 0.8): howshelfMembersand the write operations name it.name: stringThe shelf note's name.
path: stringThe shelf note's path in the vault.
rule?: stringThe cluster id whose books belonged to the shelf by rule.
group?: stringThe group folder the shelf sits in (
Books/Collections/<group>/), when it has one.members: numberHow many Calibre books are on it now (book notes without a
calibre_idaren't counted).
ShelfSuggestion interface
A shelf that suits a book, as suggestShelves ranks it.
interface ShelfSuggestion
shelf: ShelfInfoscore: numberHow well the book suits the shelf by what they are about, as Topic Map's
rankGroupsscores it (higher is closer). Before 0.8, the cosine against the mean of the shelf's books' vectors.match: numberHow well the shelf matches; suggestions are ordered by it. the same as
score(Topic Map ranks by meaning and words together).because: stringWhy, in plain words: how close the book is to the shelf's books, against the bar Topic Map judged it by, with the numbers after the words.
StartedJob interface
A background job summarizeBook started.
interface StartedJob
job: numberFor
jobStatus.run: stringThe logged run its writes go to, for
undoRun; undoing it while the job runs stops the job first.name: stringThe job's name, as the Library panel shows it.
SummaryEstimate interface
What estimateSummary gives.
interface SummaryEstimate extends Estimate
id: numbertitle: stringkind: SummaryKindchapters: numberHow many chapters the book's text has.
exists: booleanThe book's note already has a
## Summary(forsummary) or## Chapters(forchapters): a new run replaces it.
SummaryKind type
What summarizeBook writes: summary, a one-page summary in the book's note; chapters, one note per chapter.
type SummaryKind = "summary" | "chapters";
UndoReport interface
What undoing a run did.
interface UndoReport
restored: numberNotes whose fields went back.
trashed: numberFiles the run made, moved to the trash.
kept: string[]What was left as it is, in plain words: a field or note changed after the run.
stopped?: stringThe run's job was still going and was stopped first (a summary, say), in plain words.