ReadAware

Plugin API reference

A plugin is a folder with manifest.json and a built ES module. The exact public TypeScript contract ships as types/plugin-api.d.ts in the readaware-plugins repository. This page explains how its pieces fit together.

Package shape

tree
my-plugin/
  manifest.json
  main.js
  src/main.ts       # recommended and committed for review
  assets/           # optional, explicitly listed for marketplace installs

main.js default-exports a lifecycle object. ReadAware runs it in a dedicated module Worker and hands activate an actor-scoped context.

typescript
export default {
  activate(ctx) {
    // Inspect and register. Side effects are blocked in this phase.
  },
  migrate(storageCtx, change) {
    // Optional: transform plugin-private KV and documents.
  },
  deactivate() {
    // Optional: release the plugin's own external resources.
  },
};

Manifest

json
{
  "id": "theme-schedule",
  "name": "Theme Schedule",
  "version": "0.1.0",
  "schemaVersion": 1,
  "minAppVersion": "0.3.0",
  "requires": {
    "domains": { "settings": "^1.0.0" },
    "contributions": {
      "commands": "^1.0.0",
      "settingsOptions": "^1.0.0"
    },
    "services": {
      "storage": "^1.0.0",
      "schedules": "^1.0.0",
      "ui": "^1.0.0"
    },
    "schemas": { "settings": "^1.0.0" }
  },
  "settingsAccess": {
    "discover": ["appearance.theme", "reading.theme"],
    "write": ["appearance.theme", "reading.theme"]
  },
  "main": "main.js"
}
FieldContract
idLowercase letters, digits, and hyphens; maximum 64 characters. It is the permanent namespace and must equal the folder name.
name, versionUser-facing name and package version.
schemaVersionRequired positive integer for plugin-private KV and document data. Independent of package version.
requiresRequired map of capability IDs to semver ranges, grouped by domains, contributions, services, and schemas.
permissionsOptional semantic authority requested from the user. Unknown values fail validation.
settingsAccessOptional discover/read/write grants for exact setting paths or explicit section.* groups.
minAppVersionOptional app-version floor. Use it when the package depends on a newly shipped capability.
settingsOptional host-rendered plugin setting fields.
schedulesOptional recurring tasks, declared before their handlers are bound.
themes, fontsOptional declarative theme and font contributions; requires ui:themes.
mainEntry module relative to the folder; defaults to main.js.

Use the capability browser for the complete roster and permission vocabulary. A requirement is always a compatibility claim; it never grants authority.

Runtime context

NamespaceContains
ctx.manifestThe validated manifest, read-only.
ctx.appVersion, ctx.localeHost version and current UI locale.
ctx.lifecycle.phaseactivating, migrating, or active.
ctx.capabilitiesOnly the capability versions visible to this plugin actor.
ctx.domainsGranted ReadAware-owned state and behavior.
ctx.contributionsRegistries into which the plugin may supply implementations.
ctx.servicesBounded host operations and plugin-private infrastructure.

Permission-gated namespaces are absent when not granted. Every Worker call is also authorized host-side; hiding a method is not the only check. Registrations return a disposable and are reclaimed in reverse order when activation fails or the plugin is disabled.

Domains

A Domain exposes queries, optional commands, and committed events.subscribe. Commands use the same event-sourced write path as ReadAware and are attributed to plugin:<id>. Write permission implies read.

DomainQueries and commandsAuthority
libraryBooks, metadata, source chapter text, TOC, collections; import, edit, star, remove, virtual books, and collection commands.library:read / library:write
readingPer-book and aggregate reading stats; mark finished, open a book, and navigate to CFI or href.reading:read / reading:write
annotationsFilter highlights, notes, and passive ask traces; create, edit, recolor, and remove highlights or notes.annotations:read / annotations:write
conversationsRead book threads, list global threads, and read a thread. Writes stay with the chat runtime.conversations:read
settingsDiscover permitted catalog entries, read resolved values, update supported targets, and subscribe to committed changes.Exact settingsAccess grants

There is no shelf or appearance domain. Library data and active reading behavior are separate. Appearance is a section inside Settings.

Settings access

discover, read, and write are independent. Grant exact paths whenever possible; use a section group such as appearance.* only when the feature genuinely needs the whole section. Updates go through the catalog's validation, target policy, persistence, and post-commit effects.

typescript
const entries = await ctx.domains.settings.queries.discover({
  section: "appearance",
});

await ctx.domains.settings.commands.update([
  {
    path: "appearance.theme",
    value: "dark",
    target: { kind: "global" },
  },
]);

Contributions

RegistryPlugin suppliesPermission
selectionActionsSelection action and handler returning a toast or host-rendered view.None
headerActionsReader or library action, placement metadata, and view callback.None
commandsCommand metadata and handler.None
settingsOptionsDynamic options for one declared plugin field.None
voiceProvidersVoice list and encoded-audio synthesis.None
contentProvidersSections for a virtual book key.None
readerModesBounded reader segmentation mode; currently bundled-only.reader:modes
agentToolsTool schema, human label, description, and executor.agent:tools
agentContextProvidersBounded current-turn reference blocks.agent:context
agentRetrievalProvidersSearch results from plugin-owned data.agent:retrieval
memoryCandidateProvidersPossible durable facts, preferences, insights, or summaries.agent:memory
themes, fontsManifest-declared semantic theme and font data.ui:themes
syncTransportsA sync-backend session: sealed event batches, sealed blobs, and meta objects on a remote of the plugin's choosing.sync:transport

Every contribution ID is namespaced by plugin, every registration is owned and inspectable, and stale disposables cannot remove a newer replacement. A new contribution kind still needs a deliberate host consumer; after that, any compatible plugin can register without being named by the app.

Agent extension boundaries

  • Context providers run for one turn. The host adds provenance, caps size, and serializes output as untrusted reference data.
  • Retrieval providers become namespaced tools with a host-owned query/limit schema and clipped results.
  • Memory candidate providers propose bounded candidates after a turn; the host validates scope, deduplicates, and performs any durable write.

Plugins never receive the Memory port, cannot inject system rules, and cannot write long-term memory directly.

Sync transports

A syncTransports registration provides an alternative sync backend — a remote mailbox the app's sync engine pushes to and pulls from (the first-party WebDAV Sync plugin speaks WebDAV this way). The boundary is ciphertext: the engine seals every event and blob before the plugin sees it, so a transport carries opaque envelopes plus their routing fields (event id, HLC stamp) and never sees event types, book bytes, or keys. The contract is dumb storage — dense per-device event batches, blob objects in the engine's envelope formats, and create-only meta objects for first-writer-wins key material. Ordering, cursors, merge, the passphrase ritual, and scheduling stay host-side, and a transport connection is mutually exclusive with a ReadAware account. Classify failures by throwing errors that carry stable sync/* codes; anything uncoded is treated as transient and retried with backoff.

Host services

ServiceContractPermission
storageNamespaced KV, document collections, and external-change notifications.None
secretsNamespaced encrypted credential slots.None
uiHost toast and save/export flow.None
schedulesBind a handler to a manifest-declared cadence.None
sessionSubscribe to bounded reading-session facts.None
networkHost-mediated HTTP.service:network
llmOne-shot text or JSON-schema-constrained model calls using the user's configuration.service:llm
clipboardWrite text to the system clipboard.service:clipboard

Storage

Use KV for small settings and checkpoints. Use a named document collection for plugin-owned records with stable IDs and optional bookId/anchor provenance. Provenance is an index, not ownership; a document may survive deletion of the referenced book. Uninstall clears document collections but retains KV, secret slots, and committed schema metadata for reinstall and migration.

Schedules

The manifest declares { id, label, everyMinutes } and activation binds the handler through ctx.services.schedules.bind. The minimum cadence is 15 minutes. Runs happen at least at that cadence while the app is open, catch up after launch when overdue, and do not overlap. This is not a durable background job or an exact-time guarantee.

Declarative UI and settings

Plugins return versioned view data, not executable UI. The view grammar includes markdown, searchable lists, forms, detail layouts, dictionary results, and bounded block trees. Handlers may keep the surface, show a toast, open or replace a view, reset navigation, close the surface, or return field errors. The host owns loading and failure states for promises.

Manifest settings use host controls for text, textarea, number, time, select, choice, checkbox, toggle, and secret fields. Conditional fields use visibleWhen; dynamic selects use a registered settingsOptions provider. Secret fields write directly to encrypted secret slots and never enter the ordinary settings object or the agent-visible catalog.

Themes and fonts

Theme plugins declare semantic data in the manifest. An app theme overrides a fixed host token vocabulary; a reader theme supplies the required six-color page palette and optional typography defaults. The host validates values, generates CSS, loads approved local font files, and applies nothing until the user selects it.

Supplying choices needs ui:themes. Selecting one needs an exact Settings write grant such as appearance.theme or reading.theme. One does not imply the other.

Lifecycle phases

  1. Activating: queries and plugin-private reads are available; registrations are staged; side effects are blocked.
  2. Migrating: only plugin KV and document collections are available.
  3. Active: promoted handlers may use their granted domains, contributions, and services.

The host drains activation RPCs, health-checks the Worker, runs any data migration, then promotes the full staged set at one explicit point. Failed activation disposes staged work without replacing the current runtime.

Worker environment

There is no React, Jotai, DOM, WebView, Tauri, SQLite, filesystem, or process access. Ambient fetch, WebSocket, EventSource, XMLHttpRequest, BroadcastChannel, IndexedDB, and Cache Storage are disabled. Use the typed context for network, persistence, and every host interaction.

Compatibility and stability

Domains, contributions, services, and declarative schemas each carry an independent semantic version. Unknown IDs, invalid semver ranges, inaccessible required capabilities, and incompatible host versions prevent activation. Compatible additions bump the owning capability, not one global plugin API number.

The current ecosystem is first-party, so the present registry-backed contract is the baseline. Do not rely on earlier shelf, appearance, or pre-registry shapes.