Configuration Reference

Configuration

mbr uses a layered configuration system:

flowchart BT
    DEFAULTS["Compiled-in Defaults"]
    ENV["Environment Variables<br/>(MBR_*)"]
    CONFIG[".mbr/config.toml"]
    CLI["Command-line Flags"]
    FINAL["Final Configuration"]

    DEFAULTS --> ENV
    ENV --> CONFIG
    CONFIG --> CLI
    CLI --> FINAL

    style FINAL fill:#90EE90

Later layers override earlier ones.

Configuration File

Create .mbr/config.toml in your markdown repository:

# .mbr/config.toml

# Server settings
host = "127.0.0.1"
port = 5200

# Markdown settings
markdown_extensions = ["md", "markdown"]
index_file = "index.md"

# Static file folder (relative to repo root)
static_folder = "static"

# Directories to ignore during scanning
ignore_dirs = [
    "target",
    "node_modules",
    ".git",
    "build",
    "dist"
]

# File patterns to ignore
ignore_globs = [
    "*.log",
    "*.bak",
    "*.tmp"
]

# Directories ignored by file watcher (live reload)
watcher_ignore_dirs = [
    ".direnv",
    ".git",
    "target"
]

# oEmbed/OpenGraph fetch timeout in milliseconds (server/GUI default: 500)
# Note: Build mode defaults to 0 (disabled) for performance. Override with CLI if needed.
oembed_timeout_ms = 500

Configuration Options

Server Settings

OptionTypeDefaultDescription
hoststring"127.0.0.1"IP address to bind
portnumber5200Port number

Content Settings

OptionTypeDefaultDescription
markdown_extensionsarray["md"]File extensions treated as markdown
index_filestring"index.md"Default file for directories
static_folderstring"static"Folder for static file overlay

Ignore Settings

OptionTypeDefaultDescription
ignore_dirsarray(see below)Directories to skip
ignore_globsarray(see below)File patterns to ignore
watcher_ignore_dirsarray(see below)Dirs ignored by file watcher

Default ignored directories:

target, result, build, node_modules, ci, templates, .git, .github, dist, out, coverage

Default ignored globs:

*.log, *.bak, *.lock, *.sh, *.css, *.scss, *.js, *.ts

Behavior Settings

OptionTypeDefaultDescription
oembed_timeout_msnumber500 (server/GUI), 0 (build)URL metadata fetch timeout (0 to disable)
oembed_cache_sizenumber2097152Cache size in bytes (0 to disable)
skip_link_checksboolfalseSkip internal link validation during builds
link_trackingbooltrueEnable bidirectional link tracking (backlinks)
mark_incompletebool / unsetmode default (server/GUI on, build off)Highlight blocks starting with TK/TODO/FIXME/XXX
incomplete_markersarray["TK", "TODO", "FIXME", "XXX"]Marker strings that flag a block as incomplete
OptionTypeDefaultDescription
sidebar_stylestring"panel"Sidebar navigation style: "panel" (modal 3-pane) or "single" (persistent sidebar)
sidebar_max_itemsnumber100Maximum items per section in sidebar navigation
title_prefixstring""Text to prepend to all page titles
title_suffixstring""Text to append to all page titles

Sidebar styles:

Responsive behavior (single sidebar):

ViewportBehavior
>= 1024px (desktop)Sidebar appears beside content via CSS grid
< 1024px (mobile)Hamburger menu triggers slide-in drawer overlay

CSS variables for customization:

:root {
  --mbr-sidebar-width: 280px;    /* Sidebar width */
  --mbr-hide-nav-bp: 1024px;     /* Breakpoint for mobile mode */
  --mbr-show-tags: block;        /* Set to 'none' to hide tags */
}

Example configuration:

# .mbr/config.toml

# Use persistent sidebar instead of modal
sidebar_style = "single"

# Show more items in large repositories
sidebar_max_items = 200

Title Settings

OptionTypeDefaultDescription
title_prefixstring""Text prepended to all page <title> tags
title_suffixstring""Text appended to all page <title> tags

These options let you brand page titles across the site without modifying individual pages. They apply to markdown pages, directory listings, tag pages, and media viewer pages (not error pages).

Example configuration:

# .mbr/config.toml

# Brand all page titles
title_prefix = "My Notes: "
title_suffix = " | Paul's Wiki"

This turns a page titled “Getting Started” into <title>My Notes: Getting Started | Paul's Wiki</title>.

CLI usage:

mbr -s --title-prefix "My Site: " --title-suffix " | Docs" ~/notes

Tag Settings

OptionTypeDefaultDescription
tag_sourcesarray[{ field = "tags" }]Frontmatter fields to extract tags from
build_tag_pagesbooltrueGenerate tag pages in static builds

Tag source configuration:

Each tag source can specify:

Example configuration:

# .mbr/config.toml
tag_sources = [
    { field = "tags" },
    { field = "taxonomy.performers", label = "Performer", label_plural = "Performers" }
]
build_tag_pages = true

See the Tags feature documentation for complete details.

Note: Setting oembed_timeout_ms to 0 disables OpenGraph fetching entirely, rendering bare URLs as plain links. YouTube and Giphy embeds still work since they don’t require network calls.

Note: The oembed cache stores fetched page metadata to avoid redundant network requests. URLs are fetched in parallel and cached for reuse across files (in build mode) or requests (in server mode). Set oembed_cache_size to 0 to disable caching.

Build Mode Performance

By default, static builds (-b) disable oembed fetching (oembed_timeout_ms=0). If you want rich link previews in your static site, you can enable it by specifying a timeout:

mbr -b --oembed-timeout-ms 500 ~/notes

Oembed fetching is parallelized and cached, so the overhead is minimal even for large repositories.

Parallel Building

Static builds process markdown files in parallel for maximum speed:

SettingEffect
Default (auto)Uses 2x CPU cores, capped at 32
--build-concurrency 1Sequential processing (useful for debugging)
--build-concurrency 16Explicit concurrency limit

Memory usage scales with concurrency. Use lower values if running out of memory on very large repositories.

By default, static builds validate all internal links (links to other pages within the site) and report broken ones. To skip this check for faster builds:

mbr -b --skip-link-checks ~/notes

Or in .mbr/config.toml:

skip_link_checks = true

mbr automatically tracks bidirectional links between pages. The info panel (Ctrl+g) shows both:

This feature enables wiki-style backlink navigation without requiring any special syntax.

How it works:

ModeMethodPerformance
Server/GUIOn-demand grep search (cached)First request: ~1-3s, subsequent: instant
BuildEager index during renderComputed in parallel, no runtime cost

API: Each page has a links.json endpoint:

# Server mode
curl http://localhost:5200/docs/guide/links.json

# Static build
cat build/docs/guide/links.json

Response format:

{
  "inbound": [
    {"from": "/other/page/", "text": "link text", "anchor": "#section"}
  ],
  "outbound": [
    {"to": "/another/page/", "text": "link text", "anchor": "#section", "internal": true}
  ]
}

Disable link tracking:

mbr -s --no-link-tracking ~/notes

Or in .mbr/config.toml:

link_tracking = false

When disabled, the links.json endpoint returns 404 and no link files are generated during builds.

Incomplete-Block Highlighting

mbr can highlight blocks (paragraphs, headings, list items, table cells) whose first text starts with an incomplete-marker like TK, TODO, FIXME, or XXX. Highlighted blocks are wrapped in <span class="mbr-incomplete">…</span> and styled with a yellow background and dotted orange underline.

Match rule: uppercase only, word-boundary at the end of the marker. So TK, TK:, TODO foo, and FIXME(name) match; Tk, todo, Tomato, TKTK, and TODOs do not.

ModeDefaultReason
Server / GUIonHelps writers spot drafts at a glance
Static buildoffAvoids leaking unfinished markers into published sites

CLI overrides:

# Force highlighting on (e.g., during a build to preview drafts)
mbr -b --mark-incomplete ~/notes

# Force highlighting off in server mode
mbr -s --no-mark-incomplete ~/notes

Configuration file:

# .mbr/config.toml

# Force a value (overrides the per-mode default; CLI flag still wins)
mark_incomplete = true

# Customize the marker list. Markers are matched uppercase only at the
# start of a block, with a word boundary on the right edge.
incomplete_markers = ["TK", "TODO", "FIXME", "XXX"]

Environment variables:

MBR_MARK_INCOMPLETE=true
MBR_INCOMPLETE_MARKERS='["NOTE","DRAFT"]'

Setting incomplete_markers = [] disables the feature entirely (the pass becomes a no-op even when mark_incomplete = true).

Per-Page Error Indicator (Server / GUI Only)

When running with -s (server) or -g (GUI), mbr exposes a lightweight per-page diagnostics endpoint at /{page}/errors.json and a matching <mbr-page-errors> navbar indicator that lights up with a ⚠ icon when the current page has problems.

The endpoint detects three issue types in v1:

TypeTrigger
broken_internal_linkAn outbound internal link whose target does not resolve (via path_resolver). Mirrors the existing build-time link validation, but runs live and non-fatally.
broken_media_reference<img>, <video>, <audio>, or <source> whose internal src does not exist on disk or via the static-folder overlay.
unresolved_wikilinkA literal [[...]] that survived into the rendered HTML (e.g. inside a raw-HTML block). Most wikilinks are caught by broken_internal_link instead.

The response is JSON with a stable, tagged shape:

{
  "page_url": "/docs/guide/",
  "errors": [
    { "type": "broken_internal_link", "target": "/nonexistent/", "text": "bad" },
    { "type": "broken_media_reference", "src": "./missing.png", "kind": "image" },
    { "type": "unresolved_wikilink", "raw": "[[never-a-real-page]]" }
  ]
}

Status codes:

No new flags. This feature reuses the existing --no-link-tracking / link_tracking switch: disable link tracking to suppress the endpoint and hide the indicator.

Zero leakage into static builds. The endpoint is registered only in server.rs, the <mbr-page-errors> element is gated on {% if server_mode %} in templates/_nav.html, and the Lit component self-guards on window.__MBR_CONFIG__.serverMode. cargo run -- -b <repo> continues to validate links at build time via the existing --skip-link-checks flow, without emitting errors.json files or <mbr-page-errors> elements into the output.

Video Metadata Extraction

Note: This feature requires the media-metadata Cargo feature to be enabled at compile time.

mbr can extract video metadata (cover images, chapters, and captions) from video files. This works in two ways:

Server Mode (Dynamic Generation): When running with -s or -g, mbr automatically generates metadata files on-the-fly when they don’t exist on disk. Request any of these special paths to trigger generation:

PatternDescription
{video}.cover.jpgCover image (frame captured at 5 seconds, or earlier for short videos)
{video}.chapters.en.vttChapter markers in WebVTT format
{video}.captions.en.vttSubtitles/captions in WebVTT format

Example: If you have videos/demo.mp4, requesting /videos/demo.mp4.cover.jpg will dynamically extract and return a cover image.

Generated metadata is cached in memory to avoid repeated ffmpeg operations.

CLI Mode (Pre-generation): Use --extract-video-metadata to extract metadata and save as sidecar files:

# Extract metadata from a single video
mbr --extract-video-metadata ~/videos/demo.mp4

# Output:
# Analyzing video: /Users/you/videos/demo.mp4
#   Duration: 120.5s, Chapters: yes, Subtitles: no
# + Created: /Users/you/videos/demo.mp4.cover.jpg
# + Created: /Users/you/videos/demo.mp4.chapters.en.vtt
# - No captions found in video

This is useful for pre-generating metadata for static site builds or when you want the files persisted to disk.

Video Transcoding (EXPERIMENTAL)

Note: This feature requires the media-metadata Cargo feature to be enabled at compile time.

⚠️ EXPERIMENTAL - This feature is new and feedback is welcome! Please report issues or suggestions at the project repository.

mbr can dynamically transcode videos to lower resolutions (720p, 480p) using HLS (HTTP Live Streaming) for bandwidth savings on mobile devices and slow connections. This feature only works in server/GUI mode (-s or -g).

Enable transcoding:

mbr -s --transcode ~/notes

How it works:

  1. When transcoding is enabled, video embeds include multiple <source> tags with media queries
  2. Desktop browsers (viewport >= 1280px) load the original MP4 directly
  3. Tablets (viewport >= 640px) use HLS 720p playlist (Safari only)
  4. Mobile devices use HLS 480p playlist (Safari only)
  5. Non-Safari browsers fall back to the original MP4 (HLS requires JavaScript in Chrome/Firefox)
  6. HLS segments (~10 seconds each) are transcoded on-demand and cached

URL patterns:

TypeExample
Original video/videos/demo.mp4
720p HLS playlist/videos/demo-720p.m3u8
720p HLS segment/videos/demo-720p-005.ts
480p HLS playlist/videos/demo-480p.m3u8

Browser compatibility:

BrowserHLS SupportBehavior
Safari (macOS/iOS)NativeUses HLS variants on mobile/tablet
Chrome/Firefox/EdgeNoneFalls back to original MP4

Hardware acceleration: Transcoding automatically uses hardware encoders when available:

Configuration:

OptionTypeDefaultDescription
transcodeboolfalseEnable dynamic video transcoding via HLS

Memory usage: HLS segments and playlists are cached in memory (~200MB max by default). Each segment is approximately:

Cache evicts oldest segments when full, prioritizing keeping playlists cached.

When to use:

When NOT to use:

PDF Cover Extraction

Note: This feature requires the media-metadata Cargo feature to be enabled at compile time.

mbr can extract cover images (first page) from PDF files. This works in two ways:

Server Mode (Dynamic Generation): When running with -s or -g, mbr automatically generates cover images on-the-fly when requested. Request {pdf}.cover.jpg to get the cover:

PatternDescription
{pdf}.cover.jpgCover image (first page rendered at max 1200px width)

Example: If you have docs/report.pdf, requesting /docs/report.pdf.cover.jpg will dynamically extract and return the cover image.

Pre-generated covers: If a file {pdf}.cover.jpg already exists on disk (as a sidecar file), it will be served directly without extraction. This is useful for static builds.

CLI Mode (Pre-generation): Use --extract-pdf-cover to extract covers and save as sidecar files:

# Extract cover from a single PDF
mbr --extract-pdf-cover ~/docs/report.pdf

# Output:
# Extracting cover: /Users/you/docs/report.pdf -> /Users/you/docs/report.pdf.cover.jpg
# ✓ Created 1 cover image

# Extract covers from all PDFs in a directory (recursive)
mbr --extract-pdf-cover ~/docs

# Output:
# Extracting cover: docs/report.pdf -> docs/report.pdf.cover.jpg
# Extracting cover: docs/manual.pdf -> docs/manual.pdf.cover.jpg
# ✓ Created 2 cover images

Exit codes:

CodeMeaning
0Success (all covers created)
1Partial failure (some PDFs failed, others succeeded)
2Total failure (no covers created)

Error handling:

Static builds: For static site generation, pre-generate covers before building:

# 1. Extract all PDF covers
mbr --extract-pdf-cover ~/notes

# 2. Build static site (covers are included as assets)
mbr -b ~/notes

The sidecar .cover.jpg files are automatically included in static builds via asset symlinking.

Environment Variables

There are good reasons to allow this behavior, but in general, please don’t use environment variables for configs. It’s very easy to get unexpected behavior as you forget about the silent inputs from the environment.

Every configuration option can be set via environment variable with the MBR_ prefix:

# Server settings
MBR_HOST=0.0.0.0
MBR_PORT=3000

# Content settings
MBR_STATIC_FOLDER=assets
MBR_INDEX_FILE=README.md

# Behavior
MBR_OEMBED_TIMEOUT_MS=1000
MBR_OEMBED_CACHE_SIZE=4194304  # 4MB

# Video transcoding (requires media-metadata feature)
MBR_TRANSCODE=true

# Incomplete-block highlighting (TK / TODO / FIXME / XXX)
MBR_MARK_INCOMPLETE=true
MBR_INCOMPLETE_MARKERS='["NOTE","DRAFT"]'

Environment variables override config file settings.

Root Directory Detection

mbr automatically finds the repository root by searching upward for common repository markers:

Directory markers (searched first, in order):

MarkerDescription
.mbr/mbr configuration folder (highest priority)
.git/Git repository
.zk/Zettlekasten notes
.obsidian/Obsidian vault

File markers (searched if no directory markers found):

MarkerDescription
book.tomlmdBook project
mkdocs.ymlMkDocs project
docusaurus.config.jsDocusaurus project

The search works as follows:

  1. Start from the specified path
  2. Search upward for directory markers in priority order
  3. If no directory markers found, search for file markers
  4. First marker found determines the root directory
  5. If no markers found, fall back to current working directory (if ancestor) or specified path

This allows running mbr from any subdirectory:

cd ~/notes/docs/guide
mbr -s .  # Still uses ~/notes/.mbr/config.toml

Static Folder

The static_folder setting creates an overlay for serving static files. The default is static, meaning files in a static/ folder at the repo root are served at the root URL path.

notes/
├── static/               # Default static folder
│   └── images/
│       └── logo.png      # Available at /images/logo.png
└── docs/
    └── guide.md

To use a different folder, configure it in .mbr/config.toml:

static_folder = "assets"

In guide.md:

![Logo](/images/logo.png)

Path Resolution Order

  1. Check if path matches a markdown file
  2. Check if path is a directory with index file
  3. Check if path matches file in static folder
  4. Return 404

Template Folder

The --template-folder flag overrides the default template resolution:

mbr -s --template-folder ./my-theme ~/notes

Files are loaded from this folder first, falling back to compiled-in defaults if not found.

Useful for: