Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Cadmus

Cadmus is a document reader for Kobo’s e-readers.

Documentation

This site is the primary source of documentation for Cadmus. Use the sidebar to navigate, or start at the overview for installation, usage, and workflows.

Supported firmwares

Any 4.X.Y firmware, with X ≥ 6, will do.

Supported devices

  • Libra Colour.
  • Clara Colour.
  • Clara BW.
  • Elipsa 2E.
  • Clara 2E.
  • Libra 2.
  • Sage.
  • Elipsa.
  • Nia.
  • Libra H₂O.
  • Forma.
  • Clara HD.
  • Aura H₂O Edition 2.
  • Aura Edition 2.
  • Aura ONE.
  • Glo HD.
  • Aura H₂O.
  • Aura.
  • Glo.
  • Touch C.
  • Touch B.

Supported formats

  • PDF, CBZ, FB2, MOBI, XPS and TXT via MuPDF.
  • ePUB through a built-in renderer.
  • DJVU via DjVuLibre.

Features

  • Crop the margins.
  • Continuous fit-to-width zoom mode with line preserving cuts.
  • Rotate the screen (portrait ↔ landscape).
  • Adjust the contrast.
  • Define words using dictd dictionaries.
  • Annotations, highlights and bookmarks.
  • Retrieve articles from online sources through hooks.

Screenshots

Tn01 Tn02 Tn03 Tn04

Acknowledgments

Cadmus is a fork of Plato, a document reader created by Bastien Dejean.

Installation

Cadmus comes in different packages. Pick the one that matches your needs.

Available packages

PackageWhat’s includedInstalls to
KoboRoot.tgzCadmus only/mnt/onboard/.adds/cadmus
KoboRoot-nm.tgzCadmus + NickelMenu/mnt/onboard/.adds/cadmus
KoboRoot-test.tgzTest build only/mnt/onboard/.adds/cadmus-tst
KoboRoot-nm-test.tgzTest build + NickelMenu/mnt/onboard/.adds/cadmus-tst

Which one should I pick?

  • Normal installs: Use KoboRoot.tgz or KoboRoot-nm.tgz
  • If you use NickelMenu: Pick a package that includes it (-nm versions)
  • Testing a new feature: Use test packages (-test versions) for trying out changes that haven’t been released yet

First-time setup

  1. Go to the latest release.
  2. Download the package you want from the table above.
  3. Connect your Kobo to your computer via USB.
  4. Copy the downloaded file to /mnt/onboard/.kobo/KoboRoot.tgz on the device.
  5. Eject the device and reboot.

Updating

Once installed, you can update Cadmus directly through its built-in OTA feature

  • no computer required, just WiFi. See OTA updates for details.

Test builds

First-time install

  1. Open the Cadmus GitHub Actions page.
  2. Select the run for the change you want to test.
  3. Download the cadmus-kobo-test-<suffix> file. Download from GitHub Actions
  4. Extract it and pick the package that matches your setup.
  5. Copy the selected KoboRoot file to: /mnt/onboard/.kobo/KoboRoot.tgz
  6. Eject the device and reboot.

Updating an existing test build

Use the OTA feature to download updates from a PR number directly on your device. This lets you test changes without connecting to a computer.

OTA updates

Once Cadmus is installed, you can update it wirelessly without connecting to a computer. The OTA (Over-The-Air) feature downloads updates directly from GitHub.

What you need

  • A WiFi connection

For main branch or PR builds, you also need a GitHub personal access token in your Settings.toml file:

[ota]
github-token = "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Stable releases do not require a token. See the OTA settings reference for details on getting a token.

How to update

Open Main Menu → Check for Updates. You’ll see options for where to get the update from:

SourceDescription
Stable ReleaseLatest official release from GitHub
Main BranchLatest development build (most recent changes)
PR BuildTest a specific pull request

Note: The Stable Release option is not shown in test builds.

Updating from the main branch

Select Main Branch to get the most recent development build. This includes changes that have been merged but not yet released officially.

The update downloads from GitHub, installs automatically, and prompts you to reboot to finish.

Testing a pull request

Select PR Build to try out a specific change before it’s released. Enter the PR number when prompted.

This downloads the update from that pull request, installs it, and asks you to reboot.

Tip: Find the PR number in the GitHub URL. For example, in github.com/OGKevin/cadmus/pull/42 the PR number is 42.

Normal vs test builds

OTA works for both types of builds. The type you’re currently using determines what gets downloaded:

  • Normal builds update to KoboRoot.tgz in /mnt/onboard/.adds/cadmus
  • Test builds update to KoboRoot-test.tgz in /mnt/onboard/.adds/cadmus-tst

See the available packages table for all options.

First-time setup

OTA only works for updating an existing installation. To install Cadmus for the first time, follow the installation guide or the test builds guide to copy a KoboRoot file via USB.

Settings

Cadmus reads settings from Settings/Settings-*.toml. Settings can be changed on your Kobo through Main Menu → Settings, which opens the built-in settings editor.

Legend:

  • ✏️ Editable in the settings editor
  • 🔑 Required for feature to work

General Settings

keyboard-layout

✏️

Keyboard layout to use for text input.

  • Possible values: "English", "Russian".
keyboard-layout = "English"

sleep-cover

✏️

Handle the magnetic sleep cover event.

sleep-cover = true

auto-share

✏️

Automatically enter shared mode when connected to a computer.

auto-share = false

auto-suspend

✏️

Number of minutes of inactivity after which the device will automatically go to sleep.

  • Zero means never.
auto-suspend = 30.0

auto-power-off

✏️

Delay in days after which a suspended device will power off.

  • Zero means never.
auto-power-off = 3.0

button-scheme

✏️

Defines how the back and forward buttons are mapped to page forward and page backward actions.

  • Possible values: "natural", "inverted".
button-scheme = "natural"

Libraries

✏️

Document library configuration. Each library has a name, path, and mode.

[[libraries]]
name = "On Board"
path = "/mnt/onboard"
mode = "database"

libraries.name

✏️

Display name for the library.

libraries.path

✏️

Directory path containing documents.

libraries.mode

✏️

Library indexing mode.

  • Possible values: "database", "filesystem".

Intermissions

✏️

Defines the images displayed when entering an intermission state.

[intermissions]
suspend = "logo:"
power-off = "logo:"
share = "logo:"

intermissions.suspend

✏️

Image displayed when the device enters sleep mode.

  • Possible values: "logo:" (built-in logo), "cover:" (current book cover), or a path to a custom image file.

intermissions.power-off

✏️

Image displayed when the device powers off.

  • Possible values: "logo:" (built-in logo), "cover:" (current book cover), or a path to a custom image file.

intermissions.share

✏️

Image displayed when entering USB sharing mode.

  • Possible values: "logo:" (built-in logo), "cover:" (current book cover), or a path to a custom image file.

OTA

The OTA feature downloads builds from GitHub.

ota.github-token

GitHub personal access token needed to download development and test builds. Not required for stable releases.

  • Configure it under the [ota] section.
[ota]
github-token = "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

To create a token:

  1. Go to https://github.com/settings/personal-access-tokens/new
  2. Under Repository access, select Public repositories
  3. No additional permissions are required
  4. Generate and copy the token to the latest settings file in Settings

Logging

Cadmus writes JSON logs to disk. When the build enables the otel feature, it can also export logs to an OpenTelemetry endpoint.

logging

[logging]
enabled = true
level = "info"
max-files = 3
directory = "logs"
# otlp-endpoint = "https://otel.example.com:4318"

Environment overrides:

  • OTEL_EXPORTER_OTLP_ENDPOINT takes precedence over logging.otlp-endpoint.

Settings Retention

Cadmus stores each version’s settings in a separate file in the Settings/ directory (for example, Settings-v1.2.3.toml). This ensures backward and forward compatibility when you upgrade.

settings-retention

Number of recent version settings files to keep. Only the most recent N version files are kept. When a new version is saved, older versions beyond this limit are deleted automatically.

  • Default: 3
  • Set to 0 to keep all version files
settings-retention = 3

Development Environment Setup

Cadmus uses devenv with Nix to provide a reproducible development environment. This guide covers setup on both Linux and macOS.

Prerequisites

  1. Install Nix with flakes enabled. The easiest way is using the Determinate Nix Installer.
  2. Install devenv.

Quick Start

  1. Clone the repository and enter the devenv shell:

    git clone https://github.com/OGKevin/cadmus.git
    cd cadmus
    devenv shell
    
  2. Run the one-time setup to build native dependencies:

    cadmus-setup-native
    
  3. Run the emulator:

    ./run-emulator.sh
    

Available Commands

Once inside the devenv shell, these commands are available:

CommandDescription
cadmus-setup-nativeBuild MuPDF for native development (run once)
cargo testRun the test suite
./run-emulator.shRun the emulator
cadmus-build-koboBuild for Kobo device (Linux only)
cadmus-dev-otelRun emulator with OpenTelemetry instrumentation
devenv upStart observability stack (Grafana, Tempo, Loki)
cadmus-docs-buildBuild documentation portal (mdBook + Cargo docs)
cadmus-docs-serveServe documentation portal locally on port 1111

Tasks

The devenv environment uses tasks to manage build dependencies. Tasks are defined in devenv.nix and can be run with devenv tasks run <task>.

Available Tasks

TaskDescriptionDependencies
docs:buildBuild documentation EPUB (only rebuilds if files changed)None
docs:zola-buildBuild documentation portal with mdBook and Cargo docsNone
deps:nativeBuild MuPDF and wrapper for native developmentNone
build:koboBuild for Kobo device (Linux only)docs:build

How Tasks Work

Tasks with dependencies automatically run their dependencies first. For example:

# This will first run docs:build (if needed), then build for Kobo
devenv tasks run build:kobo

The docs:build task uses execIfModified to only rebuild when documentation files have actually changed.

Documentation Portal

Cadmus provides a unified documentation portal that combines user guides, API reference, and contribution guides in one place.

Building and Serving Locally

To build the documentation portal:

cadmus-docs-build

This runs the full build pipeline:

  1. Builds the mdBook user guide (docs/book/html/)
  2. Generates Rust API documentation (target/doc/)
  3. Builds the Zola landing page and integrates all documentation

To serve the portal locally with live reload:

cadmus-docs-serve

The portal will be available at http://localhost:1111 with automatic rebuilds when you change documentation files or Rust code.

Documentation Structure

The portal provides three integrated sections:

  • Landing Page (/) - Overview and feature highlights
  • User Guide (/guide/) - User-facing documentation from mdBook
  • API Reference (/api/) - Auto-generated Rust API documentation

All three sections are deployed as a single artifact to GitHub Pages at https://ogkevin.github.io/cadmus/.

Continuous Integration

Documentation is automatically built and validated on every pull request and deployed on push to main or master. The CI pipeline checks:

  • mdBook documentation compiles
  • Rust code documentation is valid
  • Zola landing page builds successfully

Running Tests

Tests require the TEST_ROOT_DIR environment variable to be set:

TEST_ROOT_DIR=$(pwd) cargo test

This is automatically configured in CI but must be set manually for local testing.

Platform Support

Linux (Full Support)

Linux provides full development capabilities including:

  • Native development (emulator, tests)
  • Cross-compilation for Kobo devices using the Linaro ARM toolchain
  • Git hooks (actionlint, shellcheck, shfmt, markdownlint, prettier)

The Linaro toolchain is automatically added to PATH and provides arm-linux-gnueabihf-* commands.

macOS (Native Development Only)

macOS supports native development but has some limitations:

FeatureStatusNotes
Native buildsSupportedEmulator and tests work
Cross-compilationNot supportedLinaro toolchain is Linux-only

macOS-Specific Notes

Cross-compilation for Kobo: The Linaro ARM cross-compilation toolchain consists of x86_64 Linux ELF binaries that cannot run on macOS. To build for Kobo devices on macOS, use Docker with a Linux container or a Linux VM.

MuPDF build: On macOS, the native setup script manually gathers pkg-config CFLAGS for system libraries because MuPDF’s build system doesn’t properly detect them on Darwin.

Observability Stack

The devenv includes a full observability stack for development:

# Start all services
devenv up

# In another terminal, run the instrumented emulator
cadmus-dev-otel

Services available after devenv up:

ServiceURLPurpose
Grafanahttp://localhost:3000Dashboards and exploration
Tempohttp://localhost:3200Distributed tracing
Lokihttp://localhost:3100Log aggregation
Prometheushttp://localhost:9090Metrics
OTLP Collectorhttp://localhost:4318Telemetry ingestion

For more details on telemetry, see OpenTelemetry Integration.

Troubleshooting

Shell takes a long time to start

The first devenv shell invocation downloads and builds dependencies, which can take several minutes. Subsequent invocations are cached and should be fast.

Tests fail with “TEST_ROOT_DIR must be set”

Set the environment variable before running tests:

TEST_ROOT_DIR=$(pwd) cargo test

Local Configuration

Create devenv.local.nix to override settings without modifying the tracked configuration:

{ pkgs, ... }:

{
  env = {
    # Example: Set TEST_ROOT_DIR automatically
    TEST_ROOT_DIR = builtins.getEnv "PWD";
  };
}

This file is gitignored and won’t affect other contributors.

OpenTelemetry Integration

Cadmus supports exporting logs and traces to OpenTelemetry-compatible backends when built with the otel feature flag.

Overview

The OpenTelemetry (OTEL) integration allows Cadmus to export both structured logs and distributed traces to observability platforms like Grafana Loki/Tempo, Jaeger, or any OTLP-compatible service. Both logs and traces are first-class features that work together to provide comprehensive observability for monitoring application behavior, debugging issues, and analyzing performance.

Architecture

The telemetry system consists of three main components:

  • Logging: JSON-structured logs written to disk via tracing_subscriber
  • Tracing: Distributed traces capturing execution flow and timing
  • OTLP Export: Optional export of both logs and traces to a remote OTLP endpoint

When the otel feature is enabled, Cadmus initializes:

  • Tracer Provider: Exports distributed traces to <endpoint>/v1/traces using batch span processors for async delivery
  • Logger Provider: Exports structured logs to <endpoint>/v1/logs using batch log processors

Each Cadmus run is assigned a unique Run ID (UUID v7) that ties together all logs and traces for that session, enabling correlation between trace spans and log events.

Building with OTEL Support

To enable OpenTelemetry, build Cadmus with the otel feature:

cargo build --features otel

Configuration

Settings File

Configure OpenTelemetry in your Settings.toml:

[logging]
enabled = true
level = "info"
max-files = 3
directory = "logs"
otlp-endpoint = "https://otel.example.com:4318"

Configuration Options

  • enabled: Enable or disable logging entirely
  • level: Minimum log level (trace, debug, info, warn, error)
  • max-files: Number of log files to retain (0 = keep all)
  • directory: Path to log directory (relative to installation directory)
  • otlp-endpoint: OTLP HTTP endpoint URL (optional)

Environment Variables

You can override the OTLP endpoint using an environment variable:

export OTEL_EXPORTER_OTLP_ENDPOINT="https://otel.example.com:4318"
./cadmus

Environment variables take precedence over Settings.toml configuration.

Log Level Control

The log level can be controlled via the RUST_LOG environment variable, which overrides the level setting:

# Enable debug logs for all modules
export RUST_LOG=debug
./cadmus

# Enable trace logs only for specific modules
export RUST_LOG=cadmus::view=trace,info
./cadmus

Distributed Tracing

Distributed tracing captures the execution flow of operations through the application, providing timing information and context about how different components interact.

How Tracing Works in Cadmus

When the otel feature is enabled, Cadmus automatically instruments key operations using the tracing crate. Each instrumented function creates a span that records:

  • Function name and module path
  • Input parameters (selectively captured)
  • Execution duration
  • Return values (at TRACE level)
  • Hierarchical relationships between spans

Spans are organized hierarchically, showing which operations triggered which other operations, making it easier to understand execution flow and identify performance bottlenecks.

Instrumentation

View components in Cadmus are instrumented at critical chokepoints:

  • handle_event methods: Capture event flow through the UI hierarchy with event type and return value
  • render methods: Capture rendering operations with rectangle dimensions for layout debugging

All instrumentation uses conditional compilation (#[cfg_attr(feature = "otel", ...)]) to ensure zero runtime overhead when the feature is disabled.

For detailed instrumentation guidelines and examples, see .github/instructions/rust-instrumentation.instructions.md.

Resource Attributes

Each telemetry export (both logs and traces) includes the following resource attributes:

  • service.name: Always cadmus
  • service.version: Git version from build metadata
  • cadmus.run_id: Unique identifier for the application run
  • hostname: System hostname

Log File Format

Logs are written as newline-delimited JSON to files named:

cadmus-<run_id>.json

Each log entry includes:

  • timestamp: ISO 8601 formatted timestamp
  • level: Log level (TRACE, DEBUG, INFO, WARN, ERROR)
  • target: Module path where the log originated
  • fields: Structured log data
  • spans: Active tracing spans providing context

Documentation Deployment

Cadmus documentation is deployed to Cloudflare Pages.

URLs

Reviewing Documentation Changes

When you open a pull request that modifies documentation files, a preview deployment is automatically created. The PR will show a deployment status with a link to the preview URL.

Preview URLs follow the pattern: https://pr-{NUMBER}.cadmus-dt6.pages.dev/

Local Development

Build and serve documentation locally:

devenv shell
cadmus-docs-build    # Build all documentation
cadmus-docs-serve    # Serve at http://localhost:1111

Or manually:

cd docs && mdbook build && cd ..
cargo doc --no-deps --document-private-items
cd docs-portal && zola serve --base-url http://localhost

Build Process

Documentation is built from three sources:

  1. mdBook (docs/) - User and contributor guides
  2. Cargo doc (crates/) - Rust API documentation
  3. Zola (docs-portal/) - Documentation portal that combines everything

The GitHub Actions workflow (.github/workflows/cadmus-docs.yml) handles building and deploying automatically on every push to main and for every pull request.