DEVELOPERS

Markdown · Wikilinks · term: Links · Hashtags · Frontmatter · Code Blocks · Images · UUIDs · Tools


Markdown

Every note body passes through the same two-stage rendering pipeline, regardless of notebook or note type.

Stage 1 — pre-processing (_renderMarkdown, before marked):

  • [[wikilinks]] and #hashtags are converted to <span> placeholders so the markdown parser never sees them as plain text.
  • Fenced code blocks and inline code are split out first, so links and tags inside backticks are left untouched.

Stage 2 — enrichment (_enrichRendered, after the HTML is in the DOM):

  • <a href> tags are classified and wired: external links get target=_blank; term: links get a terminal handler; nb-selector links navigate to the target note.
  • Wikilink <span> elements are resolved to note selectors and made clickable.
  • UUID-like strings are detected and linked.
  • Plugin-registered codeblock renderers are invoked.

[[Page Title]]
[[notebook:selector]]
[[Title|display text]]

Resolution order (both nb-web and Quartz-compatible):

  1. Exact title match (case-insensitive, via /api/list?q=)
  2. Filename stem fallback — [[1b]] resolves to 1b.md even if its title: differs

The stem fallback means title: frontmatter is free to be any descriptive string without breaking links. Bare integer IDs ([[42]]) and full nb selectors ([[preciousfinds.ca:2]]) also work, but are nb-web-only.


Clicking a term: link opens the terminal pane and runs the command.

[label](term:command%20with%20args)

Important: CommonMark disallows spaces in unquoted link URLs. Percent-encode spaces and quotes in the href; the click handler decodes them with decodeURIComponent before passing to the shell.

[hledger balance](term:hledger%20balance)
[hledger register "Bank:"](term:hledger%20register%20%22Bank:%22)

The label shown to the user is the unencoded plain text; only the URL part needs encoding.

Placeholder variables are substituted at click time:

VariableResolves to
{file}Full path of the current note
{dir}Directory containing the current note
{name}Filename stem (no extension)
{selector}nb selector of the current note
{notebook}Active notebook name
{title}Note title from frontmatter

Example — open the current note’s folder in a file manager:

[Open folder](term:xdg-open%20{dir})

Safety: term: links execute arbitrary shell commands. Only embed them in notes you control. The tutorial notes in accts:tutorial/ limit themselves to read-only hledger reporting commands.


Hashtags

#tag anywhere in note body text (outside code) is styled as a clickable tag chip. Clicking runs a notebook search for that tag. Multi-part tags using / are supported: #project/alpha.


Frontmatter

Special keys recognised by nb-web beyond standard title:, tags:, and type::

KeyValueBehaviour
pinned: yesyesNote is auto-pinned whenever it is opened, as if you had clicked the pin toolbar button. Unpinning via the toolbar also clears this key from the file.
toc: truetrueGenerates a collapsible Table of Contents at the top of the rendered note. The TOC header bar shows the note’s file path, size, and last-modified date. Headings become anchor links; clicking scrolls the page without changing the URL hash. Defaults to collapsed.
lock: yesyesMarks the note read-only in the editor. The + Add button on live codeblocks also checks this flag — it shows a 🔒 indicator for 2.5 s if clicked while locked.

Code Blocks

Two categories:

Fence languageBehaviour
ledger, journal, plain ```Static syntax highlight via Prism
hledger, tw, nb, git, t, cineLive widget — data fetched from local tools

See CODEBLOCKS for the full live-block reference.

Rule of thumb for tutorial/example content: use ```ledger (not ```hledger) so example journal entries display as static code rather than being executed against the user’s real journal.


Images

Relative image paths in notes are rewritten to /api/file?selector=… at render time, so images resolve correctly regardless of the browser’s base URL. Absolute URLs (https://) and data URIs pass through unchanged.


UUIDs

Bare UUID strings (8-4-4-4-12 hex format) in note bodies are auto-detected and rendered as linked references. Clicking resolves the UUID to its note or task.


Tools

org-to-nb-notes.py

tools/org-to-nb-notes.py — one-shot converter from an Org-mode tutorial file to a set of nb-formatted Markdown notes.

python3 tools/org-to-nb-notes.py <source.org> <nb-folder-path> [notebook-name]
 
# Example — hledger beginner tutorial into accts:tutorial/
python3 tools/org-to-nb-notes.py \
    ~/dev/awesome-hledger/contrib-resources/hledger-beginner-tutorial.org \
    ~/.nb/accts/tutorial \
    accts

Each H2 section in the org file becomes one note; the preamble (before the first H2) becomes 00_overview.md. Filenames are NN_slug.md where NN is the section sequence number.

Transformations applied:

InputOutput
Org ; prose comment linesProse text (; prefix stripped)
; lines inside code fencesPreserved — hledger comment syntax
```ledger (pandoc commonmark output)```ledger (space removed) — Prism display only, not executed
$ hledger cmd lines[cmd](term:cmd%20url%20encoded) clickable terminal link
$ hledger cmd # noteterm: link + — *note* annotation
Section title mentions in body text[[NN_slug|Title]] cross-wikilinks
H3 headings within a sectionDemoted to H2 (sub-sections stay sub-sections)

Pandoc gotchas this script handles:

  • commonmark outputs ``` ledger with a space before the language — the script strips it
  • -- flags in commands are converted to (en-dash) by pandoc smart typography — restored in _term_link
  • term: href spaces must be percent-encoded (urllib.parse.quote) — CommonMark disallows bare spaces in link URLs

Output frontmatter:

---
title: "Section Title"
type: tutorial
tags: [hledger, tutorial]
---

After writing all notes the script updates .index, then runs git add -A && git commit in the notebook root.

Dependencies: pandoc on $PATH.